Index: trunk/src/helpers/dialog.c
===================================================================
--- trunk/src/helpers/dialog.c	(revision 85)
+++ trunk/src/helpers/dialog.c	(revision 86)
@@ -1180,5 +1180,5 @@
  +          }
  *
- *
+ *@@changed V0.9.14 (2001-07-07) [umoeller]: fixed disabled mouse with hwndOwner == HWND_DESKTOP
  */
 
@@ -1381,4 +1381,11 @@
             // add "clip siblings" style
             flStyle |= WS_CLIPSIBLINGS;
+
+        if (hwndOwner == HWND_DESKTOP)
+            // there's some dumb XWorkplace code left
+            // which uses this, and this disables the
+            // mouse for some reason
+            // V0.9.14 (2001-07-07) [umoeller]
+            hwndOwner = NULLHANDLE;
 
         pDlgData->hwndDlg = WinCreateWindow(HWND_DESKTOP,
Index: trunk/src/helpers/dosh.c
===================================================================
--- trunk/src/helpers/dosh.c	(revision 85)
+++ trunk/src/helpers/dosh.c	(revision 86)
@@ -2270,8 +2270,5 @@
                                         else
                                         {
-            // **patrick, this was missing...
-            // wonder if you ever tested this, this crashes in
-            // doshPerfGet otherwise ;-)
-            /*   -----------> */            pPerfSys->palIntrs = (PLONG)malloc(pPerfSys->cProcessors * sizeof(LONG));
+                                            pPerfSys->palIntrs = (PLONG)malloc(pPerfSys->cProcessors * sizeof(LONG));
                                             if (!pPerfSys->palIntrs)
                                                 arc = ERROR_NOT_ENOUGH_MEMORY;
@@ -2284,5 +2281,5 @@
                                                     pPerfSys->padIntrPrev[ul] = 0.0;
                                                     pPerfSys->palLoads[ul] = 0;
-            /* and this one too */                  pPerfSys->palIntrs[ul] = 0;
+                                                    pPerfSys->palIntrs[ul] = 0;
                                                 }
                                             }
Index: trunk/src/helpers/helpers_pre.in
===================================================================
--- trunk/src/helpers/helpers_pre.in	(revision 85)
+++ trunk/src/helpers/helpers_pre.in	(revision 86)
@@ -42,4 +42,5 @@
 $(OUTPUTDIR)\encodings.obj \
 $(OUTPUTDIR)\linklist.obj \
+$(OUTPUTDIR)\math.obj \
 $(OUTPUTDIR)\tree.obj \
 $(OUTPUTDIR)\xml.obj \
Index: trunk/src/helpers/linklist.c
===================================================================
--- trunk/src/helpers/linklist.c	(revision 85)
+++ trunk/src/helpers/linklist.c	(revision 86)
@@ -263,5 +263,5 @@
 }
 
-#endif      // __DEBUG_MALLOC_ENABLED__
+#else       // __DEBUG_MALLOC_ENABLED__
 
 /*
@@ -286,5 +286,5 @@
  */
 
-PLINKLIST (lstCreate)(BOOL fItemsFreeable)    // in: invoke free() on the data
+PLINKLIST lstCreate(BOOL fItemsFreeable)    // in: invoke free() on the data
                                             // item pointers upon destruction?
 {
@@ -294,4 +294,6 @@
     return (pNewList);
 }
+
+#endif      // __DEBUG_MALLOC_ENABLED__
 
 /*
@@ -614,5 +616,5 @@
 }
 
-#endif // __DEBUG_MALLOC_ENABLED__
+#else  // __DEBUG_MALLOC_ENABLED__
 
 /*
@@ -626,5 +628,5 @@
  */
 
-PLISTNODE (lstAppendItem)(PLINKLIST pList,
+PLISTNODE lstAppendItem(PLINKLIST pList,
                         void* pNewItemData)     // in: data to store in list node
 {
@@ -668,4 +670,6 @@
 }
 
+#endif // __DEBUG_MALLOC_ENABLED__
+
 /*
  *@@ lstInsertItemBefore:
@@ -688,4 +692,6 @@
  *      This returns the LISTNODE of the new list item,
  *      or NULL upon errors.
+ *
+ *@@changed V0.9.14 (2001-07-14) [umoeller]: this never worked on empty lists, fixed
  */
 
@@ -716,5 +722,9 @@
                     pList->pFirst = pNewNode;
 
-                    pList->ulCount++;
+                    if (!pList->pLast)
+                        // the list was empty:
+                        pList->pLast = pNewNode;        // V0.9.14 (2001-07-14) [umoeller]
+
+                    (pList->ulCount)++;
                 }
                 else
@@ -744,5 +754,5 @@
                             pList->pLast = pNewNode;
 
-                        pList->ulCount++;
+                        (pList->ulCount)++;
                     }
                     else
Index: trunk/src/helpers/timer.c
===================================================================
--- trunk/src/helpers/timer.c	(revision 85)
+++ trunk/src/helpers/timer.c	(revision 86)
@@ -71,5 +71,5 @@
 
 /*
- *      Copyright (C) 2000 Ulrich Mller.
+ *      Copyright (C) 2000-2001 Ulrich Mller.
  *      This file is part of the "XWorkplace helpers" source package.
  *      This is free software; you can redistribute it and/or modify
@@ -109,4 +109,5 @@
 #include "helpers\except.h"
 #include "helpers\linklist.h"
+#include "helpers\math.h"
 #include "helpers\threads.h"
 #include "helpers\timer.h"
@@ -241,4 +242,5 @@
  *
  *@@added V0.9.9 (2001-03-07) [umoeller]
+ *@@changed V0.9.14 (2001-07-07) [umoeller]: added GCD optimizations
  */
 
@@ -265,15 +267,52 @@
     {
         // we have timers:
+
         ULONG ulOldPMTimeout = pSet->ulPMTimeout;
-        pSet->ulPMTimeout = 1000;
-
-        while (pNode)
-        {
+
+        if (!pNode->pNext)
+        {
+            // only one timer:
+            // that's easy
             PXTIMER pTimer = (PXTIMER)pNode->pItemData;
-
-            if ( (pTimer->ulTimeout / 2) < pSet->ulPMTimeout )
-                pSet->ulPMTimeout = pTimer->ulTimeout / 2;
-
-            pNode = pNode->pNext;
+            pSet->ulPMTimeout = pTimer->ulTimeout;
+        }
+        else if (!pNode->pNext->pNext)
+        {
+            // exactly two timers:
+            // find the greatest common denominator
+            PXTIMER pTimer1 = (PXTIMER)pNode->pItemData,
+                    pTimer2 = (PXTIMER)pNode->pNext->pItemData;
+
+            pSet->ulPMTimeout = mathGCD(pTimer1->ulTimeout,
+                                        pTimer2->ulTimeout);
+        }
+        else
+        {
+            // several timers:
+            // run through all timers and find the greatest
+            // common denominator of all frequencies...
+
+            ULONG   cTimers = lstCountItems(pllXTimers);
+            int     *paInts = (int*)_alloca(sizeof(int) * cTimers),
+                    i = 0;
+
+            _Pmpf(("Recalculating, got %d timers %d", cTimers));
+
+            // fill an array of integers with the
+            // timer frequencies
+            while (pNode)
+            {
+                PXTIMER pTimer = (PXTIMER)pNode->pItemData;
+
+                _Pmpf(("  timeout %d is %d", i, pTimer->ulTimeout));
+
+                paInts[i++] = pTimer->ulTimeout;
+
+                pNode = pNode->pNext;
+            }
+
+            pSet->ulPMTimeout = mathGCDMulti(paInts,
+                                             cTimers);
+            _Pmpf(("--> GCD is %d", pSet->ulPMTimeout));
         }
 
@@ -518,6 +557,23 @@
  *      when the window is destroyed.
  *
+ *      Note: Unless you own the timer set that
+ *      your timer runs on, it is strongly recommended
+ *      that your timer frequency is set to a multiple
+ *      of 125. The PM master timer behind the timer
+ *      set will be set to the greatest common divisor
+ *      of all frequencies, and if you set one timer
+ *      to 2000 and the other one to 2001, you will
+ *      cause quite a lot of overhead. This applies
+ *      especially to timers started by XCenter widgets.
+ *
+ *      For security, all timer frequencies will be
+ *      rounded to multiples of 25 anyway. Still,
+ *      running two timers at 1000 and 1025 will cause
+ *      the master timer to be set to 25, which is
+ *      overkill.
+ *
  *@@changed V0.9.7 (2000-12-08) [umoeller]: got rid of dtGetULongTime
  *@@changed V0.9.12 (2001-05-12) [umoeller]: added mutex protection
+ *@@changed V0.9.14 (2001-07-12) [umoeller]: now rounding freq's to multiples of 25
  */
 
@@ -540,4 +596,13 @@
             {
                 PXTIMER pTimer;
+
+                // fix the timeout... we allow only multiples of
+                // 20, and it must be at least 20 (otherwise our
+                // internal master timer calculations will fail)
+                // V0.9.14 (2001-07-07) [umoeller]
+                if (ulTimeout < 25)
+                    ulTimeout = 25;
+                else
+                    ulTimeout = (ulTimeout + 10) / 25 * 25;
 
                 // check if this timer exists already
Index: trunk/src/helpers/tree.c
===================================================================
--- trunk/src/helpers/tree.c	(revision 85)
+++ trunk/src/helpers/tree.c	(revision 86)
@@ -883,4 +883,5 @@
  *@@ treeFind:
  *      finds the tree node with the specified key.
+ *      Returns NULL if none exists.
  */
 
Index: trunk/src/helpers/xstring.c
===================================================================
--- trunk/src/helpers/xstring.c	(revision 85)
+++ trunk/src/helpers/xstring.c	(revision 86)
@@ -705,4 +705,6 @@
  *      "cReplaceWithLen" characters from pcszReplaceWith.
  *
+ *      If cReplaceWithLen is 0, characters are removed only.
+ *
  *      Returns the new length of the string, excluding
  *      the null terminator, or 0 if the replacement failed
@@ -739,4 +741,5 @@
  *@@changed V0.9.9 (2001-03-09) [umoeller]: now using xstrReserve
  *@@changed V0.9.11 (2001-04-22) [umoeller]: replaced replacement XSTRING with PCSZ
+ *@@changed V0.9.14 (2001-07-07) [umoeller]: this did nothing if cReplaceWithLen == 0, fixed
  */
 
@@ -753,5 +756,7 @@
     if (    (pxstr)         // V0.9.9 (2001-02-14) [umoeller]
          && (ulFirstReplOfs + cReplLen <= pxstr->ulLength)
-         && (pcszReplaceWith)
+         && (    (pcszReplaceWith)
+              || (cReplaceWithLen == 0)     // fixed V0.9.14 (2001-07-07) [umoeller]
+            )
        )
     {
