Ignore:
Timestamp:
Jan 5, 2002, 8:11:10 PM (24 years ago)
Author:
umoeller
Message:

Tons of updates for turbo folders and replacement icons.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/helpers/timer.c

    r123 r127  
    1212 *      to those XTimers which have elapsed.
    1313 *
    14  *      So to use XTimers, do the following:
    15  *
    16  *      1.  Create a timer set with tmrCreateSet. Specify
    17  *          an owner window and the timer ID of the master
    18  *          PM timer.
    19  *
    20  *      2.  You can then start and stop XTimers for windows
    21  *          on the same thread by calling tmrStartXTimer and
    22  *          tmrStopXTimer, respectively.
    23  *
    24  *      3.  In the window proc of the owner window, respond
    25  *          to WM_TIMER for the master PM timer by calling
    26  *          tmrTimerTick. This will call the window procs
    27  *          of those windows with WM_TIMER messages directly
    28  *          whose XTimers have elapsed.
    29  *
    3014 *      The main advantage of the XTimers is that these
    3115 *      are not a limited resource (as opposed to PM timers).
     
    3418 *      be queried with WinQuerySysValue(SV_CTIMERS).
    3519 *
     20 *      XTimers are used excessively by the default widgets
     21 *      of XWorkplace's XCenter.
     22 *
    3623 *      There are a few limitations with the XTimers though:
    37  *
    38  *      --  If you start a timer with a timeout < 100 ms,
    39  *          the first WM_TIMER might not appear before
    40  *          100 ms have elapsed. This may or be not the
    41  *          case, depending on whether other timers are
    42  *          running.
    4324 *
    4425 *      --  tmrTimerTick (which you must call when the
     
    6243 *          side, always call tmrStopAllTimers when WM_DESTROY
    6344 *          comes into a window which has used timers.
     45 *
     46 *      So to use XTimers, do the following:
     47 *
     48 *      1.  Create a timer set with tmrCreateSet. Specify
     49 *          an owner window and the timer ID of the master
     50 *          PM timer.
     51 *
     52 *      2.  You can then start and stop XTimers for windows
     53 *          on the same thread by calling tmrStartXTimer and
     54 *          tmrStopXTimer, respectively.
     55 *
     56 *      3.  In the window proc of the owner window, respond
     57 *          to WM_TIMER for the master PM timer by calling
     58 *          tmrTimerTick. This will call the window procs
     59 *          of those windows with WM_TIMER messages directly
     60 *          whose XTimers have elapsed.
    6461 *
    6562 *      Function prefixes:
     
    195192                  USHORT usTimerID)         // in: timer ID
    196193{
    197     if (pSet && pSet->pvllXTimers)
    198     {
    199         PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
     194    PLINKLIST pllXTimers;
     195    if (    (pSet)
     196         && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
     197       )
     198    {
    200199        PLISTNODE pNode = lstQueryFirstNode(pllXTimers);
    201200        while (pNode)
     
    227226                 PXTIMER pTimer)        // in: timer to remove.
    228227{
    229     if (pSet && pSet->pvllXTimers)
    230     {
    231         PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
     228    PLINKLIST pllXTimers;
     229    if (    (pSet)
     230         && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
     231       )
     232    {
    232233        lstRemoveItem(pllXTimers,
    233234                      pTimer);       // auto-free!
     
    409410        if (pSet)
    410411        {
    411             PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    412             if (pllXTimers)
     412            PLINKLIST pllXTimers;
     413            if (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
    413414            {
    414415                PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
     
    424425                pSet->pvllXTimers = NULL;
    425426            }
     427
     428            if (pSet->idPMTimerRunning)
     429            {
     430                WinStopTimer(pSet->hab,
     431                             pSet->hwndOwner,
     432                             pSet->idPMTimer);
     433                pSet->idPMTimerRunning = 0;
     434            }
     435
     436            free(pSet);
    426437        }
    427 
    428         if (pSet->idPMTimerRunning)
    429         {
    430             WinStopTimer(pSet->hab,
    431                          pSet->hwndOwner,
    432                          pSet->idPMTimer);
    433             pSet->idPMTimerRunning = 0;
    434         }
    435 
    436         free(pSet);
    437438
    438439        UnlockTimers();
     
    456457 *@@changed V0.9.14 (2001-08-01) [umoeller]: fixed mem overwrite which might have caused crashes if this got called during tmrTimerTick
    457458 *@@changed V0.9.14 (2001-08-03) [umoeller]: fixed "half frequency" regression caused by frequency optimizations
     459 *@@changed V0.9.16 (2001-12-18) [umoeller]: now using WinDispatchMsg to avoid crashes during win destruction
    458460 */
    459461
     
    462464    if (LockTimers())
    463465    {
    464         if (pSet)
    465         {
    466             PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    467             if (pllXTimers)
     466        PLINKLIST pllXTimers;
     467        if (    (pSet)
     468             && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
     469           )
     470        {
     471            // go thru all XTimers and see which one
     472            // has elapsed; for all of these, post WM_TIMER
     473            // to the target window proc
     474            PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
     475
     476            if (!pTimerNode)
    468477            {
    469                 // go thru all XTimers and see which one
    470                 // has elapsed; for all of these, post WM_TIMER
    471                 // to the target window proc
    472                 PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers);
    473 
    474                 if (!pTimerNode)
     478                // no timers left:
     479                if (pSet->idPMTimerRunning)
    475480                {
    476                     // no timers left:
    477                     if (pSet->idPMTimerRunning)
     481                    // but PM timer running:
     482                    // stop it
     483                    WinStopTimer(pSet->hab,
     484                                 pSet->hwndOwner,
     485                                 pSet->idPMTimer);
     486                    pSet->idPMTimerRunning = 0;
     487                }
     488
     489                pSet->ulPMTimeout = 0;
     490            }
     491            else
     492            {
     493                // we have timers:
     494                BOOL    fFoundInvalid = FALSE;
     495
     496                // get current time
     497                ULONG   ulTimeNow = 0;
     498                DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
     499                                &ulTimeNow, sizeof(ulTimeNow));
     500
     501                #ifdef DEBUG_XTIMERS
     502                    _Pmpf((__FUNCTION__ ": ulTimeNow = %d", ulTimeNow));
     503                #endif
     504
     505                while (pTimerNode)
     506                {
     507                    // get next node first because the
     508                    // list can get modified while processing
     509                    // V0.9.12 (2001-05-24) [umoeller]
     510                    PLISTNODE pNext = pTimerNode->pNext;
     511
     512                    PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
     513
     514                    #ifdef DEBUG_XTIMERS
     515                        _Pmpf(("   timer %d: ulNextFire = %d",
     516                                lstIndexFromItem(pllXTimers, pTimer),
     517                                pTimer->ulNextFire));
     518                    #endif
     519
     520                    if (    (pTimer)
     521                         // && (pTimer->ulNextFire < ulTimeNow)
     522                            // V0.9.14 (2001-08-01) [umoeller]
     523                            // use <= because otherwise we'll get
     524                            // only half the frequency...
     525                            // we get here frequently where the
     526                            // two values are EXACTLY equal due
     527                            // to the above optimization (DosQuerySysInfo
     528                            // called once only for the entire loop)
     529                         && (pTimer->ulNextFire <= ulTimeNow)
     530                       )
    478531                    {
    479                         // but PM timer running:
    480                         // stop it
    481                         WinStopTimer(pSet->hab,
    482                                      pSet->hwndOwner,
    483                                      pSet->idPMTimer);
    484                         pSet->idPMTimerRunning = 0;
    485                     }
    486 
    487                     pSet->ulPMTimeout = 0;
    488                 }
    489                 else
    490                 {
    491                     // we have timers:
    492                     BOOL    fFoundInvalid = FALSE;
    493 
    494                     // get current time
    495                     ULONG   ulTimeNow = 0;
    496                     DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
    497                                     &ulTimeNow, sizeof(ulTimeNow));
    498 
    499                     #ifdef DEBUG_XTIMERS
    500                         _Pmpf((__FUNCTION__ ": ulTimeNow = %d", ulTimeNow));
    501                     #endif
    502 
    503                     while (pTimerNode)
    504                     {
    505                         // get next node first because the
    506                         // list can get modified while processing
    507                         // V0.9.12 (2001-05-24) [umoeller]
    508                         PLISTNODE pNext = pTimerNode->pNext;
    509 
    510                         PXTIMER pTimer = (PXTIMER)pTimerNode->pItemData;
     532                        // this timer has elapsed:
     533                        // fire!
    511534
    512535                        #ifdef DEBUG_XTIMERS
    513                             _Pmpf(("   timer %d: ulNextFire = %d",
    514                                     lstIndexFromItem(pllXTimers, pTimer),
    515                                     pTimer->ulNextFire));
     536                            _Pmpf(("   --> fire!"));
    516537                        #endif
    517538
    518                         if (    (pTimer)
    519                              // && (pTimer->ulNextFire < ulTimeNow)
    520                                 // V0.9.14 (2001-08-01) [umoeller]
    521                                 // use <= because otherwise we'll get
    522                                 // only half the frequency...
    523                                 // we get here frequently where the
    524                                 // two values are EXACTLY equal due
    525                                 // to the above optimization (DosQuerySysInfo
    526                                 // called once only for the entire loop)
    527                              && (pTimer->ulNextFire <= ulTimeNow)
    528                            )
     539                        if (WinIsWindow(pSet->hab,
     540                                        pTimer->hwndTarget))
    529541                        {
    530                             // this timer has elapsed:
    531                             // fire!
    532 
    533                             #ifdef DEBUG_XTIMERS
    534                                 _Pmpf(("   --> fire!"));
    535                             #endif
    536 
    537                             if (WinIsWindow(pSet->hab,
    538                                             pTimer->hwndTarget))
    539                             {
    540                                 // window still valid:
    541                                 // get the window's window proc
    542                                 QMSG qmsg;
    543                                 /* PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
    544                                                                        QWP_PFNWP); */
    545 
    546                                 // moved this up V0.9.14 (2001-08-01) [umoeller]
    547                                 pTimer->ulNextFire = ulTimeNow + pTimer->ulTimeout;
    548 
    549                                 // call the window proc DIRECTLY
    550                                 qmsg.hwnd = pTimer->hwndTarget;
    551                                 qmsg.msg = WM_TIMER;
    552                                 qmsg.mp1 = (MPARAM)pTimer->usTimerID;
    553                                 qmsg.mp2 = (MPARAM)0;
    554                                 qmsg.time = 0;
    555                                 qmsg.ptl.x = 0;
    556                                 qmsg.ptl.y = 0;
    557                                 qmsg.reserved = 0;
    558                                 WinDispatchMsg(pSet->hab,
    559                                                &qmsg);
    560                                 /* pfnwp(pTimer->hwndTarget,
    561                                       WM_TIMER,
    562                                       (MPARAM)pTimer->usTimerID,
    563                                       0); */
    564                                     // V0.9.12 (2001-05-24) [umoeller]
    565                                     // if the winproc chooses to start or
    566                                     // stop a timer, pNext still points
    567                                     // to a valid node...
    568                                     // -- if a timer is removed, that's OK
    569                                     // -- if a timer is added, it is added to
    570                                     //    the list, so we'll see it in this loop
    571 
    572                                 // V0.9.14 (2001-08-01) [umoeller]
    573 
    574                                 // DO NOT REFERENCE pTimer AFTER THIS CODE;
    575                                 // tmrTimerTick might have removed the timer,
    576                                 // and since the list is auto-free, pTimer
    577                                 // might have been freed!!
    578                             }
    579                             else
    580                             {
    581                                 // window has been destroyed:
    582                                 lstRemoveNode(pllXTimers,
    583                                               pTimerNode);
    584                                     // pNext is still valid
    585 
    586                                 fFoundInvalid = TRUE;
    587                             }
    588 
    589                         } // end if (pTimer->ulNextFire < ulTimeNow)
    590 
    591                         // next timer
    592                         pTimerNode = pNext; // V0.9.12 (2001-05-24) [umoeller]
    593                     } // end while (pTimerNode)
    594 
    595                     // destroy invalid timers, if any
    596                     if (fFoundInvalid)
    597                         AdjustPMTimer(pSet);
    598 
    599                 } // end else if (!pTimerNode)
    600             } // end if (pllXTimers)
    601         } // end if (pSet)
     542                            // window still valid:
     543                            // get the window's window proc
     544                            QMSG qmsg;
     545                            /* PFNWP pfnwp = (PFNWP)WinQueryWindowPtr(pTimer->hwndTarget,
     546                                                                   QWP_PFNWP); */
     547
     548                            // moved this up V0.9.14 (2001-08-01) [umoeller]
     549                            pTimer->ulNextFire = ulTimeNow + pTimer->ulTimeout;
     550
     551                            // call the window proc DIRECTLY
     552                            // V0.9.16 (2001-12-18) [umoeller]:
     553                            // now using WinDispatchMsg to avoid crashes
     554                            // while hwndTarget is being destroyed
     555                            qmsg.hwnd = pTimer->hwndTarget;
     556                            qmsg.msg = WM_TIMER;
     557                            qmsg.mp1 = (MPARAM)pTimer->usTimerID;
     558                            qmsg.mp2 = (MPARAM)0;
     559                            qmsg.time = 0;
     560                            qmsg.ptl.x = 0;
     561                            qmsg.ptl.y = 0;
     562                            qmsg.reserved = 0;
     563                            WinDispatchMsg(pSet->hab,
     564                                           &qmsg);
     565
     566                            /* pfnwp(pTimer->hwndTarget,
     567                                  WM_TIMER,
     568                                  (MPARAM)pTimer->usTimerID,
     569                                  0); */
     570                                // V0.9.12 (2001-05-24) [umoeller]
     571                                // if the winproc chooses to start or
     572                                // stop a timer, pNext still points
     573                                // to a valid node...
     574                                // -- if a timer is removed, that's OK
     575                                // -- if a timer is added, it is added to
     576                                //    the list, so we'll see it in this loop
     577
     578                            // V0.9.14 (2001-08-01) [umoeller]
     579
     580                            // DO NOT REFERENCE pTimer AFTER THIS CODE;
     581                            // the winproc might have removed the timer,
     582                            // and since the list is auto-free, pTimer
     583                            // might have been freed!!
     584                        }
     585                        else
     586                        {
     587                            // window has been destroyed:
     588                            lstRemoveNode(pllXTimers,
     589                                          pTimerNode);
     590                                // pNext is still valid
     591
     592                            fFoundInvalid = TRUE;
     593                        }
     594
     595                    } // end if (pTimer->ulNextFire < ulTimeNow)
     596
     597                    // next timer
     598                    pTimerNode = pNext; // V0.9.12 (2001-05-24) [umoeller]
     599                } // end while (pTimerNode)
     600
     601                // destroy invalid timers, if any
     602                if (fFoundInvalid)
     603                    AdjustPMTimer(pSet);
     604
     605            } // end else if (!pTimerNode)
     606        } // end if (pllXTimers)
    602607
    603608        UnlockTimers();
     
    614619 *      XTimers is not limited.
    615620 *
    616  *      Returns a new timer or resets an existing
    617  *      timer (if usTimerID is already used with
    618  *      hwnd). Use tmrStopXTimer to stop the timer.
     621 *      Returns the ID of a new timer or resets an
     622 *      existing timer (if usTimerID is already used
     623 *      with hwnd). Use tmrStopXTimer to stop the timer.
     624 *
     625 *      Returns 0 if an error occured. It is thus
     626 *      invalid to specify a timer ID of 0.
    619627 *
    620628 *      The timer is _not_ stopped automatically
     
    644652USHORT XWPENTRY tmrStartXTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet)
    645653                               HWND hwnd,       // in: target window for XTimer
    646                                USHORT usTimerID, // in: timer ID for XTimer's WM_TIMER
     654                               USHORT usTimerID, // in: timer ID for XTimer's WM_TIMER (must be > 0)
    647655                               ULONG ulTimeout) // in: XTimer's timeout
    648656{
     
    653661    if (LockTimers())
    654662    {
    655         if (pSet)
    656         {
    657             PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    658 
    659             if ((pllXTimers) && (hwnd) && (ulTimeout))
     663        PLINKLIST pllXTimers;
     664        if (    (pSet)
     665             && (pllXTimers = (PLINKLIST)pSet->pvllXTimers)
     666             && (hwnd)
     667             && (ulTimeout)
     668             && (usTimerID)     // V0.9.16 (2001-12-18) [umoeller]
     669           )
     670        {
     671            PXTIMER pTimer;
     672            ULONG ulTimeNow;
     673
     674            // fix the timeout... we allow only multiples of
     675            // 25, and it must be at least 25 (otherwise our
     676            // internal master timer calculations will fail)
     677            // V0.9.14 (2001-07-07) [umoeller]
     678            if (ulTimeout < 25)
     679                ulTimeout = 25;
     680            else
     681                ulTimeout = (ulTimeout + 10) / 25 * 25;
     682
     683            DosQuerySysInfo(QSV_MS_COUNT,
     684                            QSV_MS_COUNT,
     685                            &ulTimeNow,
     686                            sizeof(ulTimeNow));
     687
     688            // check if this timer exists already
     689            if (pTimer = FindTimer(pSet,
     690                                   hwnd,
     691                                   usTimerID))
    660692            {
    661                 PXTIMER pTimer;
    662 
    663                 // fix the timeout... we allow only multiples of
    664                 // 25, and it must be at least 25 (otherwise our
    665                 // internal master timer calculations will fail)
    666                 // V0.9.14 (2001-07-07) [umoeller]
    667                 if (ulTimeout < 25)
    668                     ulTimeout = 25;
    669                 else
    670                     ulTimeout = (ulTimeout + 10) / 25 * 25;
    671 
    672                 // check if this timer exists already
    673                 if (pTimer = FindTimer(pSet,
    674                                        hwnd,
    675                                        usTimerID))
     693                // exists already: reset only
     694                pTimer->ulNextFire = ulTimeNow + ulTimeout;
     695                usrc = usTimerID;
     696            }
     697            else
     698            {
     699                // new timer needed:
     700                if (pTimer = NEW(XTIMER))
    676701                {
    677                     // exists already: reset only
    678                     ULONG ulTimeNow;
    679                     DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
    680                                     &ulTimeNow, sizeof(ulTimeNow));
     702                    pTimer->usTimerID = usTimerID;
     703                    pTimer->hwndTarget = hwnd;
     704                    pTimer->ulTimeout = ulTimeout;
    681705                    pTimer->ulNextFire = ulTimeNow + ulTimeout;
     706
     707                    lstAppendItem(pllXTimers,
     708                                  pTimer);
    682709                    usrc = usTimerID;
    683710                }
    684                 else
    685                 {
    686                     // new timer needed:
    687                     if (pTimer = NEW(XTIMER))
    688                     {
    689                         ULONG ulTimeNow;
    690                         DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT,
    691                                         &ulTimeNow, sizeof(ulTimeNow));
    692                         pTimer->usTimerID = usTimerID;
    693                         pTimer->hwndTarget = hwnd;
    694                         pTimer->ulTimeout = ulTimeout;
    695                         pTimer->ulNextFire = ulTimeNow + ulTimeout;
    696 
    697                         lstAppendItem(pllXTimers,
    698                                       pTimer);
    699                         usrc = usTimerID;
    700                     }
    701                 }
    702 
    703                 if (usrc)
    704                     // timer created or reset:
    705                     AdjustPMTimer(pSet);
    706 
    707             } // if ((hwnd) && (ulTimeout))
    708         }
     711            }
     712
     713            if (usrc)
     714                // timer created or reset:
     715                AdjustPMTimer(pSet);
     716
     717        } // if ((hwnd) && (ulTimeout))
    709718
    710719        UnlockTimers();
     
    733742    if (LockTimers())
    734743    {
    735         if (pSet && pSet->pvllXTimers)
    736         {
    737             // PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;
    738 
    739             PXTIMER pTimer = FindTimer(pSet,
    740                                        hwnd,
    741                                        usTimerID);
    742             if (pTimer)
    743             {
    744                 RemoveTimer(pSet, pTimer);
    745                 // recalculate
    746                 AdjustPMTimer(pSet);
    747                 brc = TRUE;
    748             }
     744        PXTIMER pTimer;
     745        if (pTimer = FindTimer(pSet,
     746                               hwnd,
     747                               usTimerID))
     748                // FindTimer checks the params
     749        {
     750            RemoveTimer(pSet, pTimer);
     751            // recalculate
     752            AdjustPMTimer(pSet);
     753            brc = TRUE;
    749754        }
    750755
Note: See TracChangeset for help on using the changeset viewer.