]> git.saurik.com Git - wxWidgets.git/blobdiff - src/os2/utils.cpp
renamed Number method (should be GetCount)
[wxWidgets.git] / src / os2 / utils.cpp
index abea758038897dad3ab8dd19b37d4ab2d9427c8b..a4531b6a12b420b56941ca814baac0782592fe8e 100644 (file)
@@ -24,7 +24,9 @@
 #include "wx/intl.h"
 
 #include <ctype.h>
-#include <direct.h>
+#ifdef __EMX__
+#include <dirent.h>
+#endif
 
 #include "wx/log.h"
 
 #include <errno.h>
 #include <stdarg.h>
 
-#define INCL_DOS
-#define INCL_PM
-#define INCL_GPI
-#include <os2.h>
 #define PURE_32
+
+#ifndef __EMX__
 #include <upm.h>
 #include <netcons.h>
 #include <netbios.h>
+#endif
 
 static const wxChar WX_SECTION[] = _T("wxWindows");
 static const wxChar eHOSTNAME[]  = _T("HostName");
@@ -65,9 +66,9 @@ bool wxGetHostName(
     char                            zServer[256];
     char                            zComputer[256];
     unsigned long                   ulLevel = 0;
-    unsigned char*                  zBuffer;
-    unsigned long                   ulBuffer;
-    unsigned long*                  pulTotalAvail;
+    unsigned char*                  zBuffer = NULL;
+    unsigned long                   ulBuffer = 256;
+    unsigned long*                  pulTotalAvail = NULL;
 
     NetBios32GetInfo( (const unsigned char*)zServer
                      ,(const unsigned char*)zComputer
@@ -104,10 +105,12 @@ bool wxGetUserId(
 , int                               nType
 )
 {
+#ifndef __EMX__
     long                            lrc;
     // UPM procs return 0 on success
     lrc = U32ELOCU((unsigned char*)zBuf, (unsigned long *)&nType);
     if (lrc == 0) return TRUE;
+#endif
     return FALSE;
 }
 
@@ -128,7 +131,8 @@ bool wxGetUserName(
 
 int wxKill(
   long                              lPid
-, int                               nSig
+, wxSignal                          eSig
+, wxKillError*                      peError
 )
 {
     return((int)::DosKillProcess(0, (PID)lPid));
@@ -160,7 +164,7 @@ bool wxShell(
     SData.PgmName  = zShell;
 
     sInputs = "/C " + rCommand;
-    SData.PgmInputs     = NULL; //(BYTE*)sInputs.c_str();
+    SData.PgmInputs     = (BYTE*)sInputs.c_str();
     SData.TermQ         = 0;
     SData.Environment   = 0;
     SData.InheritOpt    = SSF_INHERTOPT_SHELL;
@@ -177,7 +181,7 @@ bool wxShell(
     SData.ObjectBuffLen = (ULONG)sizeof(achObjBuf);
 
     rc = ::DosStartSession(&SData, &ulSessID, &vPid);
-    if (rc == 0)
+    if (rc == 0 || rc == 457) // NO_ERROR or SMG_START_IN_BACKGROUND
     {
         PTIB                            ptib;
         PPIB                            ppib;
@@ -195,10 +199,9 @@ bool wxShell(
 }
 
 // Get free memory in bytes, or -1 if cannot determine amount (e.g. on UNIX)
-long wxGetFreeMemory(
-  void*                             pMemptr
-)
+long wxGetFreeMemory()
 {
+    void*                           pMemptr = NULL;
     ULONG                           lSize;
     ULONG                           lMemFlags;
     APIRET                          rc;
@@ -210,6 +213,49 @@ long wxGetFreeMemory(
     return (long)lSize;
 }
 
+// ----------------------------------------------------------------------------
+// env vars
+// ----------------------------------------------------------------------------
+
+bool wxGetEnv(const wxString& var, wxString *value)
+{
+    // wxGetenv is defined as getenv()
+    wxChar *p = wxGetenv(var);
+    if ( !p )
+        return FALSE;
+
+    if ( value )
+    {
+        *value = p;
+    }
+
+    return TRUE;
+}
+
+bool wxSetEnv(const wxString& variable, const wxChar *value)
+{
+#if defined(HAVE_SETENV)
+    return setenv(variable.mb_str(), value ? wxString(value).mb_str().data()
+                                           : NULL, 1 /* overwrite */) == 0;
+#elif defined(HAVE_PUTENV)
+    wxString s = variable;
+    if ( value )
+        s << _T('=') << value;
+
+    // transform to ANSI
+    const char *p = s.mb_str();
+
+    // the string will be free()d by libc
+    char *buf = (char *)malloc(strlen(p) + 1);
+    strcpy(buf, p);
+
+    return putenv(buf) == 0;
+#else // no way to set an env var
+    return FALSE;
+#endif
+}
+
+
 // Sleep for nSecs seconds. Attempt a Windows implementation using timers.
 static bool inTimer = FALSE;
 
@@ -229,7 +275,7 @@ void wxUsleep(
   unsigned long                     ulMilliseconds
 )
 {
-    ::DosSleep(ulMilliseconds);
+    ::DosSleep(ulMilliseconds/1000l);
 }
 
 void wxSleep(
@@ -266,6 +312,7 @@ void wxError(
 , const wxString&                   rTitle
 )
 {
+    wxBuffer = new wxChar[256];
     wxSprintf(wxBuffer, "%s\nContinue?", WXSTRINGCAST rMsg);
     if (::WinMessageBox( HWND_DESKTOP
                         ,NULL
@@ -274,6 +321,7 @@ void wxError(
                         ,0
                         ,MB_ICONEXCLAMATION | MB_YESNO
                        ) == MBID_YES)
+    delete[] wxBuffer;
     wxExit();
 }
 
@@ -309,14 +357,17 @@ int wxGetOsVersion(
 )
 {
     ULONG                           ulSysInfo[QSV_MAX] = {0};
-
-    if (::DosQuerySysInfo( 1L
-                          ,QSV_MAX
-                          ,(PVOID)ulSysInfo
-                          ,sizeof(ULONG) * QSV_MAX
-                         ))
+    APIRET                          ulrc;
+
+    ulrc = ::DosQuerySysInfo( 1L
+                             ,QSV_MAX
+                             ,(PVOID)ulSysInfo
+                             ,sizeof(ULONG) * QSV_MAX
+                            );
+    if (ulrc == 0L)
     {
         *pMajorVsn = ulSysInfo[QSV_VERSION_MAJOR];
+        *pMajorVsn = *pMajorVsn/10;
         *pMinorVsn = ulSysInfo[QSV_VERSION_MINOR];
         return wxWINDOWS_OS2;
     }
@@ -332,8 +383,8 @@ bool wxWriteResource(
 , const wxString&                   rFile
 )
 {
-    HAB                             hab;
-    HINI                            hIni;
+    HAB                             hab = 0;
+    HINI                            hIni = 0;
 
     if (rFile != "")
     {
@@ -414,9 +465,10 @@ bool wxGetResource(
 , const wxString&                   rFile
 )
 {
-    HAB                             hab;
-    HINI                            hIni;
-    static const wxChar             zDefunkt[] = _T("$$default");
+    HAB                             hab = 0;
+    HINI                            hIni = 0;
+    wxChar                          zDefunkt[] = _T("$$default");
+    char                            zBuf[1000];
 
     if (rFile != "")
     {
@@ -427,11 +479,14 @@ bool wxGetResource(
                                               ,(PSZ)WXSTRINGCAST rSection
                                               ,(PSZ)WXSTRINGCAST rEntry
                                               ,(PSZ)zDefunkt
-                                              ,(void*)wxBuffer
+                                              ,(PVOID)zBuf
                                               ,1000
                                              );
-            if (n == 0L || wxStrcmp(wxBuffer, zDefunkt) == 0)
+            if (zBuf == NULL)
+                return FALSE;
+            if (n == 0L || wxStrcmp(zBuf, zDefunkt) == 0)
                 return FALSE;
+            zBuf[n-1] = '\0';
         }
         else
             return FALSE;
@@ -442,15 +497,16 @@ bool wxGetResource(
                                           ,(PSZ)WXSTRINGCAST rSection
                                           ,(PSZ)WXSTRINGCAST rEntry
                                           ,(PSZ)zDefunkt
-                                          ,(void*)wxBuffer
+                                          ,(PVOID)zBuf
                                           ,1000
                                          );
-        if (n == 0L || wxStrcmp(wxBuffer, zDefunkt) == 0)
+        if (zBuf == NULL)
             return FALSE;
+        if (n == 0L || wxStrcmp(zBuf, zDefunkt) == 0)
+            return FALSE;
+        zBuf[n-1] = '\0';
     }
-    if (*ppValue)
-        delete[] (*ppValue);
-    *ppValue = copystring(wxBuffer);
+    strcpy((char*)*ppValue, zBuf);
     return TRUE;
 }
 
@@ -462,6 +518,8 @@ bool wxGetResource(
 )
 {
     wxChar*                         zStr = NULL;
+
+    zStr = new wxChar[1000];
     bool                            bSucc = wxGetResource( rSection
                                                           ,rEntry
                                                           ,(wxChar **)&zStr
@@ -474,7 +532,11 @@ bool wxGetResource(
         delete[] zStr;
         return TRUE;
     }
-    else return FALSE;
+    else
+    {
+        delete[] zStr;
+        return FALSE;
+    }
 }
 
 bool wxGetResource(
@@ -485,6 +547,8 @@ bool wxGetResource(
 )
 {
     wxChar*                           zStr = NULL;
+
+    zStr = new wxChar[1000];
     bool                              bSucc = wxGetResource( rSection
                                                             ,rEntry
                                                             ,(wxChar **)&zStr
@@ -497,7 +561,11 @@ bool wxGetResource(
         delete[] zStr;
         return TRUE;
     }
-    else return FALSE;
+    else
+    {
+        delete[] zStr;
+        return FALSE;
+    }
 }
 
 bool wxGetResource(
@@ -508,6 +576,8 @@ bool wxGetResource(
 )
 {
     wxChar*                         zStr = NULL;
+
+    zStr = new wxChar[1000];
     bool                            bSucc = wxGetResource( rSection
                                                           ,rEntry
                                                           ,(wxChar **)&zStr
@@ -520,7 +590,11 @@ bool wxGetResource(
         delete[] zStr;
         return TRUE;
     }
-    else return FALSE;
+    else
+    {
+        delete[] zStr;
+        return FALSE;
+    }
 }
 #endif // wxUSE_RESOURCES
 
@@ -596,6 +670,8 @@ wxChar* wxGetUserHome (
     wxChar*                         zHome;
     wxString                        sUser1(rUser);
 
+    wxBuffer = new wxChar[256];
+#ifndef __EMX__
     if (sUser1 != _T(""))
     {
         wxChar                      zTmp[64];
@@ -610,20 +686,27 @@ wxChar* wxGetUserHome (
                 if ((zHome = wxGetenv(_T("TMP"))) != NULL    ||
                     (zHome = wxGetenv(_T("TMPDIR"))) != NULL ||
                     (zHome = wxGetenv(_T("TEMP"))) != NULL)
+                    delete[] wxBuffer;
                     return *zHome ? zHome : (wxChar*)_T("\\");
             }
             if (wxStricmp(zTmp, WXSTRINGCAST sUser1) == 0)
                 sUser1 = _T("");
         }
     }
+#endif
     if (sUser1 == _T(""))
+    {
         if ((zHome = wxGetenv(_T("HOME"))) != NULL)
         {
             wxStrcpy(wxBuffer, zHome);
             Unix2DosFilename(wxBuffer);
-            return wxBuffer;
+            wxStrcpy(zHome, wxBuffer);
+            delete[] wxBuffer;
+            return zHome;
         }
-        return NULL; // No home known!
+    }
+    delete[] wxBuffer;
+    return NULL; // No home known!
 }
 
 // Check whether this window wants to process messages, e.g. Stop button
@@ -635,8 +718,8 @@ bool wxCheckForInterrupt(
     if(pWnd)
     {
         QMSG                        vMsg;
-        HAB                         hab;
-        HWND                        hwndFilter;
+        HAB                         hab = 0;
+        HWND                        hwndFilter = NULLHANDLE;
         HWND                        hwndWin= (HWND) pWnd->GetHWND();
 
         while(::WinPeekMsg(hab, &vMsg, hwndFilter, 0, 0, PM_REMOVE))
@@ -704,14 +787,55 @@ void wxDisplaySize(
 {
     HPS                             hpsScreen;
     HDC                             hdcScreen;
+    LONG                            lWidth;
+    LONG                            lHeight;
 
     hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
     hdcScreen = ::GpiQueryDevice(hpsScreen);
-    ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, (PLONG)pWidth);
-    ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, (PLONG)pHeight);
+    ::DevQueryCaps(hdcScreen, CAPS_WIDTH, 1L, &lWidth);
+    ::DevQueryCaps(hdcScreen, CAPS_HEIGHT, 1L, &lHeight);
     DevCloseDC(hdcScreen);
+    *pWidth = (int)lWidth;
+    *pHeight = (int)lHeight;
 }
 
+void wxDisplaySizeMM(
+  int*                              pWidth
+, int*                              pHeight
+)
+{
+    HPS                             hpsScreen;
+    HDC                             hdcScreen;
+
+    hpsScreen = ::WinGetScreenPS(HWND_DESKTOP);
+    hdcScreen = ::GpiQueryDevice(hpsScreen);
+
+    if (pWidth)
+        ::DevQueryCaps( hdcScreen
+                       ,CAPS_HORIZONTAL_RESOLUTION
+                       ,1L
+                       ,(PLONG)pWidth
+                      );
+    if (pHeight)
+        ::DevQueryCaps( hdcScreen
+                       ,CAPS_VERTICAL_RESOLUTION
+                       ,1L
+                       ,(PLONG)pHeight
+                      );
+}
+
+void wxClientDisplayRect(int *x, int *y, int *width, int *height)
+{
+    // This is supposed to return desktop dimensions minus any window
+    // manager panels, menus, taskbars, etc.  If there is a way to do that
+    // for this platform please fix this function, otherwise it defaults
+    // to the entire desktop.
+    if (x) *x = 0;
+    if (y) *y = 0;
+    wxDisplaySize(width, height);
+}
+
+
 bool wxDirExists(
   const wxString&                   rDir
 )
@@ -769,3 +893,300 @@ WXWORD WXDLLEXPORT wxGetWindowId(
     return ::WinQueryWindowUShort((HWND)hWnd, QWS_ID);
 }
 
+wxString WXDLLEXPORT wxPMErrorToStr(
+  ERRORID                           vError
+)
+{
+    wxString                        sError;
+
+    //
+    // Remove the high order byte -- it is useless
+    //
+    vError &= 0x0000ffff;
+    switch(vError)
+    {
+        case PMERR_INVALID_HWND:
+            sError = wxT("Invalid window handle specified");
+            break;
+
+        case PMERR_INVALID_FLAG:
+            sError = wxT("Invalid flag bit set");
+            break;
+
+        case PMERR_NO_MSG_QUEUE:
+            sError = wxT("No message queue available");
+            break;
+
+        case PMERR_INVALID_PARM:
+            sError = wxT("Parameter contained invalid data");
+            break;
+
+        case PMERR_INVALID_PARAMETERS:
+            sError = wxT("Parameter value is out of range");
+            break;
+
+        case PMERR_PARAMETER_OUT_OF_RANGE:
+            sError = wxT("Parameter value is out of range");
+            break;
+
+        case PMERR_INVALID_INTEGER_ATOM:
+            sError = wxT("Not a valid atom");
+            break;
+
+        case PMERR_INVALID_HATOMTBL:
+            sError = wxT("Atom table handle is invalid");
+            break;
+
+        case PMERR_INVALID_ATOM_NAME:
+            sError = wxT("Not a valid atom name");
+            break;
+
+        case PMERR_ATOM_NAME_NOT_FOUND:
+            sError = wxT("Valid name format, but cannot find name in atom table");
+            break;
+
+        default:
+            sError = wxT("Unknown error");
+    }
+    return(sError);
+} // end of wxPMErrorToStr
+
+void wxDrawBorder(
+  HPS                               hPS
+, RECTL&                            rRect
+, WXDWORD                           dwStyle
+)
+{
+    POINTL                          vPoint[2];
+
+    vPoint[0].x = rRect.xLeft;
+    vPoint[0].y = rRect.yBottom;
+    ::GpiMove(hPS, &vPoint[0]);
+    if (dwStyle & wxSIMPLE_BORDER ||
+        dwStyle & wxSTATIC_BORDER)
+    {
+        vPoint[1].x = rRect.xRight - 1;
+        vPoint[1].y = rRect.yTop - 1;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+    }
+    if (dwStyle & wxSUNKEN_BORDER)
+    {
+        LINEBUNDLE                      vLineBundle;
+
+        vLineBundle.lColor     = 0x00FFFFFF; // WHITE
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[1].x = rRect.xRight - 1;
+        vPoint[1].y = rRect.yTop - 1;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+       vPoint[0].x = rRect.xLeft + 1;
+       vPoint[0].y = rRect.yBottom + 1;
+       ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xRight - 2;
+        vPoint[1].y = rRect.yTop - 2;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+
+        vLineBundle.lColor     = 0x00000000; // BLACK
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[0].x = rRect.xLeft + 2;
+        vPoint[0].y = rRect.yBottom + 2;
+        ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xLeft + 2;
+        vPoint[1].y = rRect.yTop - 3;
+        ::GpiLine(hPS, &vPoint[1]);
+        vPoint[1].x = rRect.xRight - 3;
+        vPoint[1].y = rRect.yTop - 3;
+        ::GpiLine(hPS, &vPoint[1]);
+
+        vPoint[0].x = rRect.xLeft + 3;
+        vPoint[0].y = rRect.yBottom + 3;
+        ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xLeft + 3;
+        vPoint[1].y = rRect.yTop - 4;
+        ::GpiLine(hPS, &vPoint[1]);
+        vPoint[1].x = rRect.xRight - 4;
+        vPoint[1].y = rRect.yTop - 4;
+        ::GpiLine(hPS, &vPoint[1]);
+    }
+    if (dwStyle & wxDOUBLE_BORDER)
+    {
+        LINEBUNDLE                      vLineBundle;
+
+        vLineBundle.lColor     = 0x00FFFFFF; // WHITE
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[1].x = rRect.xRight - 1;
+        vPoint[1].y = rRect.yTop - 1;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+        vLineBundle.lColor     = 0x00000000; // WHITE
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[0].x = rRect.xLeft + 2;
+        vPoint[0].y = rRect.yBottom + 2;
+        ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xRight - 2;
+        vPoint[1].y = rRect.yTop - 2;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+        vLineBundle.lColor     = 0x00FFFFFF; // BLACK
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[0].x = rRect.xLeft + 3;
+        vPoint[0].y = rRect.yBottom + 3;
+        ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xRight - 3;
+        vPoint[1].y = rRect.yTop - 3;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+    }
+    if (dwStyle & wxRAISED_BORDER)
+    {
+        LINEBUNDLE                      vLineBundle;
+
+        vLineBundle.lColor     = 0x00000000; // BLACK
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[1].x = rRect.xRight - 1;
+        vPoint[1].y = rRect.yTop - 1;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+       vPoint[0].x = rRect.xLeft + 1;
+       vPoint[0].y = rRect.yBottom + 1;
+       ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xRight - 2;
+        vPoint[1].y = rRect.yTop - 2;
+        ::GpiBox( hPS
+                 ,DRO_OUTLINE
+                 ,&vPoint[1]
+                 ,0L
+                 ,0L
+                );
+
+        vLineBundle.lColor     = 0x00FFFFFF; // WHITE
+        vLineBundle.usMixMode  = FM_OVERPAINT;
+        vLineBundle.fxWidth    = 2;
+        vLineBundle.lGeomWidth = 2;
+        vLineBundle.usType     = LINETYPE_SOLID;
+        vLineBundle.usEnd      = 0;
+        vLineBundle.usJoin     = 0;
+        ::GpiSetAttrs( hPS
+                      ,PRIM_LINE
+                      ,LBB_COLOR | LBB_MIX_MODE | LBB_WIDTH | LBB_GEOM_WIDTH | LBB_TYPE
+                      ,0L
+                      ,&vLineBundle
+                     );
+        vPoint[0].x = rRect.xLeft + 2;
+        vPoint[0].y = rRect.yBottom + 2;
+        ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xLeft + 2;
+        vPoint[1].y = rRect.yTop - 3;
+        ::GpiLine(hPS, &vPoint[1]);
+        vPoint[1].x = rRect.xRight - 3;
+        vPoint[1].y = rRect.yTop - 3;
+        ::GpiLine(hPS, &vPoint[1]);
+
+        vPoint[0].x = rRect.xLeft + 3;
+        vPoint[0].y = rRect.yBottom + 3;
+        ::GpiMove(hPS, &vPoint[0]);
+        vPoint[1].x = rRect.xLeft + 3;
+        vPoint[1].y = rRect.yTop - 4;
+        ::GpiLine(hPS, &vPoint[1]);
+        vPoint[1].x = rRect.xRight - 4;
+        vPoint[1].y = rRect.yTop - 4;
+        ::GpiLine(hPS, &vPoint[1]);
+    }
+} // end of wxDrawBorder
+