]> git.saurik.com Git - wxWidgets.git/commitdiff
merged optimizations from 2.2
authorVadim Zeitlin <vadim@wxwidgets.org>
Sat, 21 Apr 2001 01:46:19 +0000 (01:46 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sat, 21 Apr 2001 01:46:19 +0000 (01:46 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9820 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/msw/regconf.h
include/wx/msw/registry.h
src/common/log.cpp
src/common/wincmn.cpp
src/msw/regconf.cpp
src/msw/registry.cpp
src/msw/utils.cpp

index 8cad906888c9d3fc52f6056b3fdce791815f4308..5ed19b74e185830b1a732d84e36dbe73f8061cac 100644 (file)
@@ -29,10 +29,10 @@ class WXDLLEXPORT wxRegConfig : public wxConfigBase
 public:
   // ctor & dtor
     // will store data in HKLM\appName and HKCU\appName
 public:
   // ctor & dtor
     // will store data in HKLM\appName and HKCU\appName
-  wxRegConfig(const wxString& appName = "",
-              const wxString& vendorName = "",
-              const wxString& localFilename = "",
-              const wxString& globalFilename = "",
+  wxRegConfig(const wxString& appName = _T(""),
+              const wxString& vendorName = _T(""),
+              const wxString& localFilename = _T(""),
+              const wxString& globalFilename = _T(""),
               long style = 0);
 
     // dtor will save unsaved data
               long style = 0);
 
     // dtor will save unsaved data
@@ -65,37 +65,37 @@ public:
   // read/write
   bool Read(const wxString& key, wxString *pStr) const;
   bool Read(const wxString& key, wxString *pStr, const wxString& szDefault) const;
   // read/write
   bool Read(const wxString& key, wxString *pStr) const;
   bool Read(const wxString& key, wxString *pStr, const wxString& szDefault) const;
-       wxString Read(const wxString& key, const wxString& defVal) const
-                       { return wxConfigBase::Read(key, defVal); }
-  
+  wxString Read(const wxString& key, const wxString& defVal) const
+      { return wxConfigBase::Read(key, defVal); }
+
   bool Read(const wxString& key, long *plResult) const;
   bool Read(const wxString& key, long *plResult) const;
-       bool Read(const wxString& key, long *pl, long defVal) const
-                       { return wxConfigBase::Read(key, pl, defVal); }
+  bool Read(const wxString& key, long *pl, long defVal) const
+      { return wxConfigBase::Read(key, pl, defVal); }
   long Read(const wxString& key, long defVal) const
   long Read(const wxString& key, long defVal) const
-                       { return wxConfigBase::Read(key, defVal); }
-  
+      { return wxConfigBase::Read(key, defVal); }
+
   // The following are necessary to satisfy the compiler
   bool Read(const wxString& key, int *pi, int defVal) const
   // The following are necessary to satisfy the compiler
   bool Read(const wxString& key, int *pi, int defVal) const
-                       { return wxConfigBase::Read(key, pi, defVal); }
-       bool Read(const wxString& key, int *pi) const
-                       { return wxConfigBase::Read(key, pi); }
-
-       bool Read(const wxString& key, double* val, double defVal) const
-                       { return wxConfigBase::Read(key, val, defVal); }
-       bool Read(const wxString& key, double* val) const
-                       { return wxConfigBase::Read(key, val); }
-  
-       bool Read(const wxString& key, bool *pb, bool defVal) const
-                       { return wxConfigBase::Read(key, pb, defVal); }
-       bool Read(const wxString& key, bool *pb) const
-                       { return wxConfigBase::Read(key, pb); }
-  
+      { return wxConfigBase::Read(key, pi, defVal); }
+  bool Read(const wxString& key, int *pi) const
+      { return wxConfigBase::Read(key, pi); }
+
+  bool Read(const wxString& key, double* val, double defVal) const
+      { return wxConfigBase::Read(key, val, defVal); }
+  bool Read(const wxString& key, double* val) const
+      { return wxConfigBase::Read(key, val); }
+
+  bool Read(const wxString& key, bool *pb, bool defVal) const
+      { return wxConfigBase::Read(key, pb, defVal); }
+  bool Read(const wxString& key, bool *pb) const
+      { return wxConfigBase::Read(key, pb); }
+
   bool Write(const wxString& key, const wxString& szValue);
   bool Write(const wxString& key, long lValue);
   bool Write(const wxString& key, const wxString& szValue);
   bool Write(const wxString& key, long lValue);
-       bool Write(const wxString& key, double dValue)
-                       { return wxConfigBase::Write(key, dValue); }
-       bool Write(const wxString& key, bool bValue)
-                       { return wxConfigBase::Write(key, bValue); }
+  bool Write(const wxString& key, double dValue)
+      { return wxConfigBase::Write(key, dValue); }
+  bool Write(const wxString& key, bool bValue)
+      { return wxConfigBase::Write(key, bValue); }
 
   virtual bool Flush(bool /* bCurrentOnly = FALSE */ ) { return TRUE; }
 
 
   virtual bool Flush(bool /* bCurrentOnly = FALSE */ ) { return TRUE; }
 
@@ -108,6 +108,21 @@ public:
   virtual bool DeleteGroup(const wxString& key);
   virtual bool DeleteAll();
 
   virtual bool DeleteGroup(const wxString& key);
   virtual bool DeleteAll();
 
+protected:
+  // opens the local key creating it if necessary and returns it
+  wxRegKey& LocalKey() const // must be const to be callable from const funcs
+  {
+      wxRegConfig* self = wxConstCast(this, wxRegConfig);
+
+      if ( !m_keyLocal.IsOpened() )
+      {
+          // create on demand
+          self->m_keyLocal.Create();
+      }
+
+      return self->m_keyLocal;
+  }
+
 private:
   // no copy ctor/assignment operator
   wxRegConfig(const wxRegConfig&);
 private:
   // no copy ctor/assignment operator
   wxRegConfig(const wxRegConfig&);
index 1a6bf68fcf4c3eb5dcbf15d005c367aa30a20087..76980b5f649139e45aedd8066fc1c40baa24d61a 100644 (file)
 #pragma interface "registry.h"
 #endif
 
 #pragma interface "registry.h"
 #endif
 
-// ----------------------------------------------------------------------------
-// mutable hack (see also registry.cpp)
-// ----------------------------------------------------------------------------
-#if   wxUSE_MUTABLE
-  #define MUTABLE mutable
-#else
-  #define MUTABLE
-#endif
-
 // ----------------------------------------------------------------------------
 // types used in this module
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // types used in this module
 // ----------------------------------------------------------------------------
@@ -217,7 +208,17 @@ public:
   bool  GetFirstKey  (wxString& strKeyName  , long& lIndex);
   bool  GetNextKey   (wxString& strKeyName  , long& lIndex) const;
 
   bool  GetFirstKey  (wxString& strKeyName  , long& lIndex);
   bool  GetNextKey   (wxString& strKeyName  , long& lIndex) const;
 
+  // for wxRegConfig usage only: preallocate some memory for the name
+  void ReserveMemoryForName(size_t bytes) { m_strKey.reserve(bytes); }
+
 private:
 private:
+  // common part of all ctors
+  void Init()
+  {
+    m_hKey = (WXHKEY) NULL;
+    m_dwLastError = 0;
+  }
+
   // no copy ctor/assignment operator
   wxRegKey(const wxRegKey& key);            // not implemented
   wxRegKey& operator=(const wxRegKey& key); // not implemented
   // no copy ctor/assignment operator
   wxRegKey(const wxRegKey& key);            // not implemented
   wxRegKey& operator=(const wxRegKey& key); // not implemented
@@ -226,7 +227,7 @@ private:
               m_hRootKey;       // handle of the top key (i.e. StdKey)
   wxString    m_strKey;         // key name (relative to m_hRootKey)
 
               m_hRootKey;       // handle of the top key (i.e. StdKey)
   wxString    m_strKey;         // key name (relative to m_hRootKey)
 
-  MUTABLE long m_dwLastError;   // last error (0 if none)
+  long        m_dwLastError;    // last error (0 if none)
 };
 
 #endif  //_REGISTRY_H
 };
 
 #endif  //_REGISTRY_H
index 97f406c81fecf62391a083c200a3c4f3d91769b5..0f30a9e562502016902a98b240dc1bed1d8e2ef3 100644 (file)
@@ -96,6 +96,12 @@ static wxCriticalSection gs_csLogBuf;
 
 #endif // wxUSE_THREADS
 
 
 #endif // wxUSE_THREADS
 
+// return true if we have a non NULL non disabled log target
+static inline bool IsLoggingEnabled()
+{
+    return wxLog::IsEnabled() && (wxLog::GetActiveTarget() != NULL);
+}
+
 // ----------------------------------------------------------------------------
 // implementation of Log functions
 //
 // ----------------------------------------------------------------------------
 // implementation of Log functions
 //
@@ -106,6 +112,7 @@ static wxCriticalSection gs_csLogBuf;
 // generic log function
 void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
 {
 // generic log function
 void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
 {
+<<<<<<< log.cpp
   if ( wxLog::GetActiveTarget() != NULL ) {
     wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
   if ( wxLog::GetActiveTarget() != NULL ) {
     wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
@@ -113,24 +120,38 @@ void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...)
     va_start(argptr, szFormat);
     wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
     va_end(argptr);
     va_start(argptr, szFormat);
     wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
     va_end(argptr);
+=======
+    if ( IsLoggingEnabled() ) {
+        wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
+>>>>>>> 1.93.2.3
 
 
+<<<<<<< log.cpp
     wxLog::OnLog(level, s_szBuf, time(NULL));
   }
     wxLog::OnLog(level, s_szBuf, time(NULL));
   }
+=======
+        va_list argptr;
+        va_start(argptr, szFormat);
+        wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
+        va_end(argptr);
+
+        wxLog::OnLog(level, s_szBuf, time(NULL));
+    }
+>>>>>>> 1.93.2.3
 }
 
 }
 
-#define IMPLEMENT_LOG_FUNCTION(level)                             \
-  void wxLog##level(const wxChar *szFormat, ...)                  \
-  {                                                               \
-    if ( wxLog::GetActiveTarget() != NULL ) {                     \
-      wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                    \
-                                                                  \
-      va_list argptr;                                             \
-      va_start(argptr, szFormat);                                 \
-      wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);  \
-      va_end(argptr);                                             \
-                                                                  \
-      wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));           \
-    }                                                             \
+#define IMPLEMENT_LOG_FUNCTION(level)                               \
+  void wxLog##level(const wxChar *szFormat, ...)                    \
+  {                                                                 \
+    if ( IsLoggingEnabled() ) {                                     \
+      wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                      \
+                                                                    \
+      va_list argptr;                                               \
+      va_start(argptr, szFormat);                                   \
+      wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);    \
+      va_end(argptr);                                               \
+                                                                    \
+      wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));             \
+    }                                                               \
   }
 
 IMPLEMENT_LOG_FUNCTION(FatalError)
   }
 
 IMPLEMENT_LOG_FUNCTION(FatalError)
@@ -143,41 +164,41 @@ IMPLEMENT_LOG_FUNCTION(Status)
 // same as info, but only if 'verbose' mode is on
 void wxLogVerbose(const wxChar *szFormat, ...)
 {
 // same as info, but only if 'verbose' mode is on
 void wxLogVerbose(const wxChar *szFormat, ...)
 {
-  wxLog *pLog = wxLog::GetActiveTarget();
-  if ( pLog != NULL && pLog->GetVerbose() ) {
-    wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
+    if ( IsLoggingEnabled() ) {
+        wxLog *pLog = wxLog::GetActiveTarget();
+        if ( pLog != NULL && pLog->GetVerbose() ) {
+            wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
 
-    va_list argptr;
-    va_start(argptr, szFormat);
-    wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
-    va_end(argptr);
+            va_list argptr;
+            va_start(argptr, szFormat);
+            wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
+            va_end(argptr);
 
 
-    wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL));
-  }
+            wxLog::OnLog(wxLOG_Info, s_szBuf, time(NULL));
+        }
+    }
 }
 
 // debug functions
 #ifdef __WXDEBUG__
 }
 
 // debug functions
 #ifdef __WXDEBUG__
-#define IMPLEMENT_LOG_DEBUG_FUNCTION(level)                       \
-  void wxLog##level(const wxChar *szFormat, ...)                  \
-  {                                                               \
-    if ( wxLog::GetActiveTarget() != NULL ) {                     \
-      wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                    \
-                                                                  \
-      va_list argptr;                                             \
-      va_start(argptr, szFormat);                                 \
-      wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);  \
-      va_end(argptr);                                             \
-                                                                  \
-      wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));           \
-    }                                                             \
+#define IMPLEMENT_LOG_DEBUG_FUNCTION(level)                         \
+  void wxLog##level(const wxChar *szFormat, ...)                    \
+  {                                                                 \
+    if ( IsLoggingEnabled() ) {                                     \
+      wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);                      \
+                                                                    \
+      va_list argptr;                                               \
+      va_start(argptr, szFormat);                                   \
+      wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);    \
+      va_end(argptr);                                               \
+                                                                    \
+      wxLog::OnLog(wxLOG_##level, s_szBuf, time(NULL));             \
+    }                                                               \
   }
 
   void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
   {
   }
 
   void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...)
   {
-    wxLog *pLog = wxLog::GetActiveTarget();
-
-    if ( pLog != NULL && wxLog::IsAllowedTraceMask(mask) ) {
+    if ( IsLoggingEnabled() && wxLog::IsAllowedTraceMask(mask) ) {
       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
       wxChar *p = s_szBuf;
       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
       wxChar *p = s_szBuf;
@@ -205,12 +226,10 @@ void wxLogVerbose(const wxChar *szFormat, ...)
 
   void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
   {
 
   void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...)
   {
-    wxLog *pLog = wxLog::GetActiveTarget();
-
     // we check that all of mask bits are set in the current mask, so
     // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
     // if both bits are set.
     // we check that all of mask bits are set in the current mask, so
     // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something
     // if both bits are set.
-    if ( pLog != NULL && ((pLog->GetTraceMask() & mask) == mask) ) {
+    if ( IsLoggingEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) {
       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
       va_list argptr;
       wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
       va_list argptr;
@@ -245,26 +264,30 @@ void wxLogSysErrorHelper(long lErrCode)
 
 void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
 {
 
 void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...)
 {
-    wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
+    if ( IsLoggingEnabled() ) {
+        wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
 
-    va_list argptr;
-    va_start(argptr, szFormat);
-    wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
-    va_end(argptr);
+        va_list argptr;
+        va_start(argptr, szFormat);
+        wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
+        va_end(argptr);
 
 
-    wxLogSysErrorHelper(wxSysErrorCode());
+        wxLogSysErrorHelper(wxSysErrorCode());
+    }
 }
 
 void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
 {
 }
 
 void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...)
 {
-    wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
+    if ( IsLoggingEnabled() ) {
+        wxCRIT_SECT_LOCKER(locker, gs_csLogBuf);
 
 
-    va_list argptr;
-    va_start(argptr, szFormat);
-    wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
-    va_end(argptr);
+        va_list argptr;
+        va_start(argptr, szFormat);
+        wxVsnprintf(s_szBuf, WXSIZEOF(s_szBuf), szFormat, argptr);
+        va_end(argptr);
 
 
-    wxLogSysErrorHelper(lErrCode);
+        wxLogSysErrorHelper(lErrCode);
+    }
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
index 59f3a09ffbf009254038513d8797706520dcbbee..1e8541a0b0caa70e7e9b39c3ddc469ed3d71dc25 100644 (file)
@@ -127,14 +127,12 @@ void wxWindowBase::InitBase()
 #endif // wxUSE_VALIDATORS
 
     // use the system default colours
 #endif // wxUSE_VALIDATORS
 
     // use the system default colours
-    wxSystemSettings settings;
-
-    m_backgroundColour = settings.GetSystemColour(wxSYS_COLOUR_BTNFACE);
-    // m_foregroundColour = *wxBLACK;  // TODO take this from sys settings too?
+    m_backgroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE);
     m_foregroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
 
     // GRG, changed Mar/2000
     m_foregroundColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
 
     // GRG, changed Mar/2000
-    m_font = settings.GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
+    m_font = wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT);
+
     // no style bits
     m_exStyle =
     m_windowStyle = 0;
     // no style bits
     m_exStyle =
     m_windowStyle = 0;
index 9c77482ec94a9d8bfab359f9856683947f9acc55..34a60f02bd5c9c18bf9c81f30a5723a676ab5c8b 100644 (file)
@@ -112,14 +112,28 @@ wxRegConfig::wxRegConfig(const wxString& appName, const wxString& vendorName,
   //else: we don't need to do all the complicated stuff above
 
   wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
   //else: we don't need to do all the complicated stuff above
 
   wxString str = strLocal.IsEmpty() ? strRoot : strLocal;
+
+  // as we're going to change the name of these keys fairly often and as
+  // there are only few of wxRegConfig objects (usually 1), we can allow
+  // ourselves to be generous and spend some memory to significantly improve
+  // performance of SetPath()
+  static const size_t MEMORY_PREALLOC = 512;
+
+  m_keyLocalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
+  m_keyLocal.ReserveMemoryForName(MEMORY_PREALLOC);
+
   m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
   m_keyLocalRoot.SetName(wxRegKey::HKCU, SOFTWARE_KEY + str);
-  m_keyLocal.SetName(m_keyLocalRoot, "");
+  m_keyLocal.SetName(m_keyLocalRoot, _T(""));
 
   if ( bDoUseGlobal )
   {
     str = strGlobal.IsEmpty() ? strRoot : strGlobal;
 
   if ( bDoUseGlobal )
   {
     str = strGlobal.IsEmpty() ? strRoot : strGlobal;
+
+    m_keyGlobalRoot.ReserveMemoryForName(MEMORY_PREALLOC);
+    m_keyGlobal.ReserveMemoryForName(MEMORY_PREALLOC);
+
     m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
     m_keyGlobalRoot.SetName(wxRegKey::HKLM, SOFTWARE_KEY + str);
-    m_keyGlobal.SetName(m_keyGlobalRoot, "");
+    m_keyGlobal.SetName(m_keyGlobalRoot, _T(""));
   }
 
   // Create() will Open() if key already exists
   }
 
   // Create() will Open() if key already exists
@@ -146,50 +160,222 @@ wxRegConfig::~wxRegConfig()
 // ----------------------------------------------------------------------------
 // path management
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // path management
 // ----------------------------------------------------------------------------
+
+// this function is called a *lot* of times (as I learned after seeing from
+// profiler output that it is called ~12000 times from Mahogany start up code!)
+// so it is important to optimize it - in particular, avoid using generic
+// string functions here and do everything manually because it is faster
+//
+// I still kept the old version to be able to check that the optimized code has
+// the same output as the non optimized version.
 void wxRegConfig::SetPath(const wxString& strPath)
 {
 void wxRegConfig::SetPath(const wxString& strPath)
 {
-  wxArrayString aParts;
+    // remember the old path
+    wxString strOldPath = m_strPath;
 
 
-  // because GetPath() returns "" when we're at root, we must understand
-  // empty string as "/"
-  if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
-    // absolute path
-    wxSplitPath(aParts, strPath);
-  }
-  else {
-    // relative path, combine with current one
-    wxString strFullPath = GetPath();
-    strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
-    wxSplitPath(aParts, strFullPath);
-  }
+#ifdef WX_DEBUG_SET_PATH // non optimized version kept here for testing
+    wxString m_strPathAlt;
 
 
-  // recombine path parts in one variable
-  wxString strOldPath = m_strPath, strRegPath;
-  m_strPath.Empty();
-  for ( size_t n = 0; n < aParts.Count(); n++ ) {
-    strRegPath << '\\' << aParts[n];
-    m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n];
-  }
+    {
+        wxArrayString aParts;
+
+        // because GetPath() returns "" when we're at root, we must understand
+        // empty string as "/"
+        if ( strPath.IsEmpty() || (strPath[0] == wxCONFIG_PATH_SEPARATOR) ) {
+            // absolute path
+            wxSplitPath(aParts, strPath);
+        }
+        else {
+            // relative path, combine with current one
+            wxString strFullPath = GetPath();
+            strFullPath << wxCONFIG_PATH_SEPARATOR << strPath;
+            wxSplitPath(aParts, strFullPath);
+        }
+
+        // recombine path parts in one variable
+        wxString strRegPath;
+        m_strPathAlt.Empty();
+        for ( size_t n = 0; n < aParts.Count(); n++ ) {
+            strRegPath << '\\' << aParts[n];
+            m_strPathAlt << wxCONFIG_PATH_SEPARATOR << aParts[n];
+        }
+    }
+#endif // 0
 
 
-  if ( m_strPath == strOldPath )
-      return;
+    // check for the most common case first
+    if ( strPath.empty() )
+    {
+        m_strPath = wxCONFIG_PATH_SEPARATOR;
+    }
+    else // not root
+    {
+        // construct the full path
+        wxString strFullPath;
+        if ( strPath[0u] == wxCONFIG_PATH_SEPARATOR )
+        {
+            // absolute path
+            strFullPath = strPath;
+        }
+        else // relative path
+        {
+            strFullPath.reserve(2*m_strPath.length());
+
+            strFullPath << m_strPath << wxCONFIG_PATH_SEPARATOR << strPath;
+        }
+
+        // simplify it: we need to handle ".." here
+
+        // count the total number of slashes we have to know if we can go upper
+        size_t totalSlashes = 0;
+
+        // position of the last slash to be able to backtrack to it quickly if
+        // needed, but we set it to -1 if we don't have a valid position
+        //
+        // we only remember the last position which means that we handle ".."
+        // quite efficiently but not "../.." - however the latter should be
+        // much more rare, so it is probably ok
+        int posLastSlash = -1;
+
+        const wxChar *src = strFullPath.c_str();
+        size_t len = strFullPath.length();
+        const wxChar *end = src + len;
+
+        wxChar *dst = m_strPath.GetWriteBuf(len);
+        wxChar *start = dst;
+
+        for ( ; src < end; src++, dst++ )
+        {
+            if ( *src == wxCONFIG_PATH_SEPARATOR )
+            {
+                // check for "/.."
+
+                // note that we don't have to check for src < end here as
+                // *end == 0 so can't be '.'
+                if ( src[1] == _T('.') && src[2] == _T('.') &&
+                     (src + 3 == end || src[3] == wxCONFIG_PATH_SEPARATOR) )
+                {
+                    if ( !totalSlashes )
+                    {
+                        wxLogWarning(_("'%s' has extra '..', ignored."),
+                                     strFullPath.c_str());
+                    }
+                    else // return to the previous path component
+                    {
+                        // do we already have its position?
+                        if ( posLastSlash == -1 )
+                        {
+                            // no, find it: note that we are sure to have one
+                            // because totalSlashes > 0 so we don't have to
+                            // check the boundary condition below
+
+                            // this is more efficient than strrchr()
+                            while ( *dst != wxCONFIG_PATH_SEPARATOR )
+                            {
+                                dst--;
+                            }
+                        }
+                        else // the position of last slash was stored
+                        {
+                            // go directly there
+                            dst = start + posLastSlash;
+
+                            // invalidate posLastSlash
+                            posLastSlash = -1;
+                        }
+
+                        // this shouldn't happen
+                        wxASSERT_MSG( *dst == wxCONFIG_PATH_SEPARATOR,
+                                      _T("error in wxRegConfig::SetPath") );
+
+                        // we killed one
+                        totalSlashes--;
+                    }
+
+                    // skip both dots
+                    src += 2;
+                }
+                else // not "/.."
+                {
+                    if ( (dst == start) || (dst[-1] != wxCONFIG_PATH_SEPARATOR) )
+                    {
+                        *dst = wxCONFIG_PATH_SEPARATOR;
+
+                        posLastSlash = dst - start;
+
+                        totalSlashes++;
+                    }
+                    //else: nothing to do, we squeeze several subseuquent
+                    //      slashes into one
+                }
+            }
+            else // normal character
+            {
+                // just copy
+                *dst = *src;
+            }
+        }
+
+        // NUL terminate the string
+        if ( dst[-1] == wxCONFIG_PATH_SEPARATOR && (dst != start + 1) )
+        {
+            // if it has a trailing slash we remove it unless it is the only
+            // string character
+            dst--;
+        }
+
+        *dst = _T('\0');
+
+        m_strPath.UngetWriteBuf(dst - start);
+    }
 
 
-  // as we create the registry key when SetPath(key) is done, we can be left
-  // with plenty of empty keys if this was only done to try to read some value
-  // which, in fact, doesn't exist - to prevent this from happening we
-  // automatically delete the old key if it was empty
-  if ( m_keyLocal.IsEmpty() )
-  {
-      m_keyLocal.DeleteSelf();
-  }
+#ifdef WX_DEBUG_SET_PATH
+    wxASSERT( m_strPath == m_strPathAlt );
+#endif
+
+    if ( m_strPath == strOldPath )
+        return;
+
+    // registry APIs want backslashes instead of slashes
+    wxString strRegPath;
+    size_t len = m_strPath.length();
 
 
-  // change current key(s)
-  m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
-  m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
-  m_keyLocal.Create();
+    const wxChar *src = m_strPath.c_str();
+    wxChar *dst = strRegPath.GetWriteBuf(len);
+
+    const wxChar *end = src + len;
+    for ( ; src < end; src++, dst++ )
+    {
+        if ( *src == wxCONFIG_PATH_SEPARATOR )
+            *dst = _T('\\');
+        else
+            *dst = *src;
+    }
+
+    strRegPath.UngetWriteBuf(len);
+
+    // this is not needed any longer as we don't create keys unnecessarily any
+    // more (now it is done on demand, i.e. only when they're going to contain
+    // something)
+#if 0
+    // as we create the registry key when SetPath(key) is done, we can be left
+    // with plenty of empty keys if this was only done to try to read some
+    // value which, in fact, doesn't exist - to prevent this from happening we
+    // automatically delete the old key if it was empty
+    if ( m_keyLocal.Exists() && LocalKey().IsEmpty() )
+    {
+        m_keyLocal.DeleteSelf();
+    }
+#endif // 0
 
 
-  wxLogNull nolog;
-  m_keyGlobal.Open();
+    // change current key(s)
+    m_keyLocal.SetName(m_keyLocalRoot, strRegPath);
+    m_keyGlobal.SetName(m_keyGlobalRoot, strRegPath);
+
+    // don't create it right now, wait until it is accessed
+    //m_keyLocal.Create();
+
+    wxLogNull nolog;
+    m_keyGlobal.Open();
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -219,7 +405,7 @@ bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
   if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
     // try to find a global entry which doesn't appear locally
     while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
   if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
     // try to find a global entry which doesn't appear locally
     while ( m_keyGlobal.GetNextKey(str, lIndex) ) {
-      if ( !m_keyLocal.HasSubKey(str) ) {
+      if ( !m_keyLocal.Exists() || !LocalKey().HasSubKey(str) ) {
         // ok, found one - return it
         return TRUE;
       }
         // ok, found one - return it
         return TRUE;
       }
@@ -229,10 +415,14 @@ bool wxRegConfig::GetNextGroup(wxString& str, long& lIndex) const
     lIndex |= LOCAL_MASK;
   }
 
     lIndex |= LOCAL_MASK;
   }
 
+  // if we don't have the key at all, don't try to enumerate anything under it
+  if ( !m_keyLocal.Exists() )
+      return FALSE;
+
   // much easier with local entries: get the next one we find
   // (don't forget to clear our flag bit and set it again later)
   lIndex &= ~LOCAL_MASK;
   // much easier with local entries: get the next one we find
   // (don't forget to clear our flag bit and set it again later)
   lIndex &= ~LOCAL_MASK;
-  bool bOk = m_keyLocal.GetNextKey(str, lIndex);
+  bool bOk = LocalKey().GetNextKey(str, lIndex);
   lIndex |= LOCAL_MASK;
 
   return bOk;
   lIndex |= LOCAL_MASK;
 
   return bOk;
@@ -250,7 +440,7 @@ bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
   if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
     // try to find a global entry which doesn't appear locally
     while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
   if ( m_keyGlobal.IsOpened() && !IS_LOCAL_INDEX(lIndex) ) {
     // try to find a global entry which doesn't appear locally
     while ( m_keyGlobal.GetNextValue(str, lIndex) ) {
-      if ( !m_keyLocal.HasValue(str) ) {
+      if ( !m_keyLocal.Exists() || !LocalKey().HasValue(str) ) {
         // ok, found one - return it
         return TRUE;
       }
         // ok, found one - return it
         return TRUE;
       }
@@ -260,10 +450,14 @@ bool wxRegConfig::GetNextEntry(wxString& str, long& lIndex) const
     lIndex |= LOCAL_MASK;
   }
 
     lIndex |= LOCAL_MASK;
   }
 
+  // if we don't have the key at all, don't try to enumerate anything under it
+  if ( !m_keyLocal.Exists() )
+      return FALSE;
+
   // much easier with local entries: get the next one we find
   // (don't forget to clear our flag bit and set it again later)
   lIndex &= ~LOCAL_MASK;
   // much easier with local entries: get the next one we find
   // (don't forget to clear our flag bit and set it again later)
   lIndex &= ~LOCAL_MASK;
-  bool bOk = m_keyLocal.GetNextValue(str, lIndex);
+  bool bOk = LocalKey().GetNextValue(str, lIndex);
   lIndex |= LOCAL_MASK;
 
   return bOk;
   lIndex |= LOCAL_MASK;
 
   return bOk;
@@ -313,7 +507,8 @@ bool wxRegConfig::HasGroup(const wxString& key) const
 
     wxString strName(path.Name());
 
 
     wxString strName(path.Name());
 
-    return m_keyLocal.HasSubKey(strName) || m_keyGlobal.HasSubKey(strName);
+    return (m_keyLocal.Exists() && LocalKey().HasSubKey(strName)) ||
+           m_keyGlobal.HasSubKey(strName);
 }
 
 bool wxRegConfig::HasEntry(const wxString& key) const
 }
 
 bool wxRegConfig::HasEntry(const wxString& key) const
@@ -322,7 +517,8 @@ bool wxRegConfig::HasEntry(const wxString& key) const
 
     wxString strName(path.Name());
 
 
     wxString strName(path.Name());
 
-    return m_keyLocal.HasValue(strName) || m_keyGlobal.HasValue(strName);
+    return (m_keyLocal.Exists() && LocalKey().HasValue(strName)) ||
+           m_keyGlobal.HasValue(strName);
 }
 
 wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
 }
 
 wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
@@ -332,7 +528,7 @@ wxConfigBase::EntryType wxRegConfig::GetEntryType(const wxString& key) const
     wxString strName(path.Name());
 
     bool isNumeric;
     wxString strName(path.Name());
 
     bool isNumeric;
-    if ( m_keyLocal.HasValue(strName) )
+    if ( m_keyLocal.Exists() && LocalKey().HasValue(strName) )
         isNumeric = m_keyLocal.IsNumericValue(strName);
     else if ( m_keyGlobal.HasValue(strName) )
         isNumeric = m_keyGlobal.IsNumericValue(strName);
         isNumeric = m_keyLocal.IsNumericValue(strName);
     else if ( m_keyGlobal.HasValue(strName) )
         isNumeric = m_keyGlobal.IsNumericValue(strName);
@@ -356,7 +552,7 @@ bool wxRegConfig::Read(const wxString& key, wxString *pStr) const
   // overriden by the local key with the same name
   if ( IsImmutable(path.Name()) ) {
     if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
   // overriden by the local key with the same name
   if ( IsImmutable(path.Name()) ) {
     if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
-      if ( m_keyLocal.HasValue(path.Name()) ) {
+      if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
                    path.Name().c_str());
       }
         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
                    path.Name().c_str());
       }
@@ -370,7 +566,7 @@ bool wxRegConfig::Read(const wxString& key, wxString *pStr) const
   }
 
   // first try local key
   }
 
   // first try local key
-  if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
+  if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) ||
        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
     // nothing to do
 
        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
     // nothing to do
 
@@ -392,7 +588,7 @@ bool wxRegConfig::Read(const wxString& key, wxString *pStr,
   // overriden by the local key with the same name
   if ( IsImmutable(path.Name()) ) {
     if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
   // overriden by the local key with the same name
   if ( IsImmutable(path.Name()) ) {
     if ( TryGetValue(m_keyGlobal, path.Name(), *pStr) ) {
-      if ( m_keyLocal.HasValue(path.Name()) ) {
+      if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
                    path.Name().c_str());
       }
         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
                    path.Name().c_str());
       }
@@ -406,7 +602,7 @@ bool wxRegConfig::Read(const wxString& key, wxString *pStr,
   }
 
   // first try local key
   }
 
   // first try local key
-  if ( TryGetValue(m_keyLocal, path.Name(), *pStr) ||
+  if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), *pStr)) ||
        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
     *pStr = wxConfigBase::ExpandEnvVars(*pStr);
     return TRUE;
        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), *pStr)) ) {
     *pStr = wxConfigBase::ExpandEnvVars(*pStr);
     return TRUE;
@@ -435,7 +631,7 @@ bool wxRegConfig::Read(const wxString& key, long *plResult) const
   // overriden by the local key with the same name
   if ( IsImmutable(path.Name()) ) {
     if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
   // overriden by the local key with the same name
   if ( IsImmutable(path.Name()) ) {
     if ( TryGetValue(m_keyGlobal, path.Name(), plResult) ) {
-      if ( m_keyLocal.HasValue(path.Name()) ) {
+      if ( m_keyLocal.Exists() && LocalKey().HasValue(path.Name()) ) {
         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
                      path.Name().c_str());
       }
         wxLogWarning(wxT("User value for immutable key '%s' ignored."),
                      path.Name().c_str());
       }
@@ -449,7 +645,7 @@ bool wxRegConfig::Read(const wxString& key, long *plResult) const
   }
 
   // first try local key
   }
 
   // first try local key
-  if ( TryGetValue(m_keyLocal, path.Name(), plResult) ||
+  if ( (m_keyLocal.Exists() && TryGetValue(LocalKey(), path.Name(), plResult)) ||
        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
     return TRUE;
   }
        (bQueryGlobal && TryGetValue(m_keyGlobal, path.Name(), plResult)) ) {
     return TRUE;
   }
@@ -465,7 +661,7 @@ bool wxRegConfig::Write(const wxString& key, const wxString& szValue)
     return FALSE;
   }
 
     return FALSE;
   }
 
-  return m_keyLocal.SetValue(path.Name(), szValue);
+  return LocalKey().SetValue(path.Name(), szValue);
 }
 
 bool wxRegConfig::Write(const wxString& key, long lValue)
 }
 
 bool wxRegConfig::Write(const wxString& key, long lValue)
@@ -477,7 +673,7 @@ bool wxRegConfig::Write(const wxString& key, long lValue)
     return FALSE;
   }
 
     return FALSE;
   }
 
-  return m_keyLocal.SetValue(path.Name(), lValue);
+  return LocalKey().SetValue(path.Name(), lValue);
 }
 
 // ----------------------------------------------------------------------------
 }
 
 // ----------------------------------------------------------------------------
@@ -548,13 +744,15 @@ bool wxRegConfig::DeleteEntry(const wxString& value, bool bGroupIfEmptyAlso)
 {
   wxConfigPathChanger path(this, value);
 
 {
   wxConfigPathChanger path(this, value);
 
-  if ( !m_keyLocal.DeleteValue(path.Name()) )
-    return FALSE;
+  if ( m_keyLocal.Exists() ) {
+    if ( !m_keyLocal.DeleteValue(path.Name()) )
+      return FALSE;
 
 
-  if ( m_keyLocal.IsEmpty() ) {
-    wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
-    SetPath("..");  // changes m_keyLocal
-    return m_keyLocal.DeleteKey(strKey);
+    if ( m_keyLocal.IsEmpty() ) {
+      wxString strKey = GetPath().AfterLast(wxCONFIG_PATH_SEPARATOR);
+      SetPath("..");  // changes m_keyLocal
+      return LocalKey().DeleteKey(strKey);
+    }
   }
 
   return TRUE;
   }
 
   return TRUE;
@@ -564,7 +762,7 @@ bool wxRegConfig::DeleteGroup(const wxString& key)
 {
   wxConfigPathChanger path(this, key);
 
 {
   wxConfigPathChanger path(this, key);
 
-  return m_keyLocal.DeleteKey(path.Name());
+  return m_keyLocal.Exists() ? LocalKey().DeleteKey(path.Name()) : TRUE;
 }
 
 bool wxRegConfig::DeleteAll()
 }
 
 bool wxRegConfig::DeleteAll()
index 978d7ee4faa7e2464f44185fd866e380ce4ff808..b0c061c1d0f5c53fbbe1940c8af69a6a6a43b775 100644 (file)
@@ -91,12 +91,12 @@ aStdKeys[] =
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 // macros
 // ----------------------------------------------------------------------------
-// @ const_cast<> is not yet supported by all compilers
+
+// const_cast<> is not yet supported by all compilers
 #define CONST_CAST    ((wxRegKey *)this)->
 
 #define CONST_CAST    ((wxRegKey *)this)->
 
-#if   !USE_MUTABLE
-  #define m_dwLastError   CONST_CAST m_dwLastError
-#endif
+// and neither is mutable which m_dwLastError should be
+#define m_dwLastError   CONST_CAST m_dwLastError
 
 // ----------------------------------------------------------------------------
 // non member functions
 
 // ----------------------------------------------------------------------------
 // non member functions
@@ -186,16 +186,16 @@ wxRegKey::StdKey wxRegKey::GetStdKeyFromHkey(WXHKEY hkey)
 
 wxRegKey::wxRegKey()
 {
 
 wxRegKey::wxRegKey()
 {
-  m_hKey = 0;
   m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
   m_hRootKey = (WXHKEY) aStdKeys[HKCR].hkey;
-  m_dwLastError = 0;
+
+  Init();
 }
 
 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
 {
   m_hRootKey  = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
 }
 
 wxRegKey::wxRegKey(const wxString& strKey) : m_strKey(strKey)
 {
   m_hRootKey  = (WXHKEY) aStdKeys[ExtractKeyName(m_strKey)].hkey;
-  m_hKey      = (WXHKEY) NULL;
-  m_dwLastError = 0;
+
+  Init();
 }
 
 // parent is a predefined (and preopened) key
 }
 
 // parent is a predefined (and preopened) key
@@ -203,8 +203,8 @@ wxRegKey::wxRegKey(StdKey keyParent, const wxString& strKey) : m_strKey(strKey)
 {
   RemoveTrailingSeparator(m_strKey);
   m_hRootKey  = (WXHKEY) aStdKeys[keyParent].hkey;
 {
   RemoveTrailingSeparator(m_strKey);
   m_hRootKey  = (WXHKEY) aStdKeys[keyParent].hkey;
-  m_hKey      = (WXHKEY) NULL;
-  m_dwLastError = 0;
+
+  Init();
 }
 
 // parent is a normal regkey
 }
 
 // parent is a normal regkey
@@ -221,8 +221,8 @@ wxRegKey::wxRegKey(const wxRegKey& keyParent, const wxString& strKey)
   RemoveTrailingSeparator(m_strKey);
 
   m_hRootKey  = keyParent.m_hRootKey;
   RemoveTrailingSeparator(m_strKey);
 
   m_hRootKey  = keyParent.m_hRootKey;
-  m_hKey      = (WXHKEY) NULL;
-  m_dwLastError = 0;
+
+  Init();
 }
 
 // dtor closes the key releasing system resource
 }
 
 // dtor closes the key releasing system resource
@@ -260,7 +260,14 @@ void wxRegKey::SetName(const wxRegKey& keyParent, const wxString& strKey)
   Close();
 
   // combine our name with parent's to get the full name
   Close();
 
   // combine our name with parent's to get the full name
-  m_strKey = keyParent.m_strKey;
+
+  // NB: this method is called by wxRegConfig::SetPath() which is a performance
+  //     critical function and so it preallocates space for our m_strKey to
+  //     gain some speed - this is why we only use += here and not = which
+  //     would just free the prealloc'd buffer and would have to realloc it the
+  //     next line!
+  m_strKey.clear();
+  m_strKey += keyParent.m_strKey;
   if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
     m_strKey += REG_SEPARATOR;
   m_strKey += strKey;
   if ( !strKey.IsEmpty() && strKey[0] != REG_SEPARATOR )
     m_strKey += REG_SEPARATOR;
   m_strKey += strKey;
@@ -408,16 +415,14 @@ bool wxRegKey::Close()
 {
   if ( IsOpened() ) {
     m_dwLastError = RegCloseKey((HKEY) m_hKey);
 {
   if ( IsOpened() ) {
     m_dwLastError = RegCloseKey((HKEY) m_hKey);
+    m_hKey = 0;
+
     if ( m_dwLastError != ERROR_SUCCESS ) {
       wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
                     GetName().c_str());
 
     if ( m_dwLastError != ERROR_SUCCESS ) {
       wxLogSysError(m_dwLastError, _("Can't close registry key '%s'"),
                     GetName().c_str());
 
-      m_hKey = 0;
       return FALSE;
     }
       return FALSE;
     }
-    else {
-      m_hKey = 0;
-    }
   }
 
   return TRUE;
   }
 
   return TRUE;
index f5217d22f960e6c2880672a406f61c4c6b94a6e4..b7a6ae1a48c71419bedb470556dda19ef0c0b446 100644 (file)
@@ -990,10 +990,22 @@ void wxGetMousePosition( int* x, int* y )
 // Return TRUE if we have a colour display
 bool wxColourDisplay()
 {
 // Return TRUE if we have a colour display
 bool wxColourDisplay()
 {
-    ScreenHDC dc;
-    int noCols = GetDeviceCaps(dc, NUMCOLORS);
+    // this function is called from wxDC ctor so it is called a *lot* of times
+    // hence we optimize it a bit but doign the check only once
+    //
+    // this should be MT safe as only the GUI thread (holding the GUI mutex)
+    // can call us
+    static int s_isColour = -1;
+
+    if ( s_isColour == -1 )
+    {
+        ScreenHDC dc;
+        int noCols = ::GetDeviceCaps(dc, NUMCOLORS);
+
+        s_isColour = (noCols == -1) || (noCols > 2);
+    }
 
 
-    return (noCols == -1) || (noCols > 2);
+    return s_isColour != 0;
 }
 
 // Returns depth of screen
 }
 
 // Returns depth of screen