Changeset 127 for trunk/src/helpers/timer.c
- Timestamp:
- Jan 5, 2002, 8:11:10 PM (24 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/timer.c
r123 r127 12 12 * to those XTimers which have elapsed. 13 13 * 14 * So to use XTimers, do the following:15 *16 * 1. Create a timer set with tmrCreateSet. Specify17 * an owner window and the timer ID of the master18 * PM timer.19 *20 * 2. You can then start and stop XTimers for windows21 * on the same thread by calling tmrStartXTimer and22 * tmrStopXTimer, respectively.23 *24 * 3. In the window proc of the owner window, respond25 * to WM_TIMER for the master PM timer by calling26 * tmrTimerTick. This will call the window procs27 * of those windows with WM_TIMER messages directly28 * whose XTimers have elapsed.29 *30 14 * The main advantage of the XTimers is that these 31 15 * are not a limited resource (as opposed to PM timers). … … 34 18 * be queried with WinQuerySysValue(SV_CTIMERS). 35 19 * 20 * XTimers are used excessively by the default widgets 21 * of XWorkplace's XCenter. 22 * 36 23 * 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 before40 * 100 ms have elapsed. This may or be not the41 * case, depending on whether other timers are42 * running.43 24 * 44 25 * -- tmrTimerTick (which you must call when the … … 62 43 * side, always call tmrStopAllTimers when WM_DESTROY 63 44 * 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. 64 61 * 65 62 * Function prefixes: … … 195 192 USHORT usTimerID) // in: timer ID 196 193 { 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 { 200 199 PLISTNODE pNode = lstQueryFirstNode(pllXTimers); 201 200 while (pNode) … … 227 226 PXTIMER pTimer) // in: timer to remove. 228 227 { 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 { 232 233 lstRemoveItem(pllXTimers, 233 234 pTimer); // auto-free! … … 409 410 if (pSet) 410 411 { 411 PLINKLIST pllXTimers = (PLINKLIST)pSet->pvllXTimers;412 if (pllXTimers )412 PLINKLIST pllXTimers; 413 if (pllXTimers = (PLINKLIST)pSet->pvllXTimers) 413 414 { 414 415 PLISTNODE pTimerNode = lstQueryFirstNode(pllXTimers); … … 424 425 pSet->pvllXTimers = NULL; 425 426 } 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); 426 437 } 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);437 438 438 439 UnlockTimers(); … … 456 457 *@@changed V0.9.14 (2001-08-01) [umoeller]: fixed mem overwrite which might have caused crashes if this got called during tmrTimerTick 457 458 *@@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 458 460 */ 459 461 … … 462 464 if (LockTimers()) 463 465 { 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) 468 477 { 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) 475 480 { 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 ) 478 531 { 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! 511 534 512 535 #ifdef DEBUG_XTIMERS 513 _Pmpf((" timer %d: ulNextFire = %d", 514 lstIndexFromItem(pllXTimers, pTimer), 515 pTimer->ulNextFire)); 536 _Pmpf((" --> fire!")); 516 537 #endif 517 538 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)) 529 541 { 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) 602 607 603 608 UnlockTimers(); … … 614 619 * XTimers is not limited. 615 620 * 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. 619 627 * 620 628 * The timer is _not_ stopped automatically … … 644 652 USHORT XWPENTRY tmrStartXTimer(PXTIMERSET pSet, // in: timer set (from tmrCreateSet) 645 653 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) 647 655 ULONG ulTimeout) // in: XTimer's timeout 648 656 { … … 653 661 if (LockTimers()) 654 662 { 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)) 660 692 { 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)) 676 701 { 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; 681 705 pTimer->ulNextFire = ulTimeNow + ulTimeout; 706 707 lstAppendItem(pllXTimers, 708 pTimer); 682 709 usrc = usTimerID; 683 710 } 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)) 709 718 710 719 UnlockTimers(); … … 733 742 if (LockTimers()) 734 743 { 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; 749 754 } 750 755
Note:
See TracChangeset
for help on using the changeset viewer.