Files
Mozilla/mozilla/widget/timer/src/windows/nsTimer.cpp
2000-01-21 21:56:09 +00:00

254 lines
5.2 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
* Michael Lowe <michael.lowe@bigfoot.com>
*/
#include "nsWindowsTimer.h"
#include "nsITimerQueue.h"
#include "nsIWindowsTimerMap.h"
#include "nsCRT.h"
#include "prlog.h"
#include <stdio.h>
#include <windows.h>
#include <limits.h>
#include "nsWidgetsCID.h"
#include "nsIServiceManager.h"
#include <stdlib.h>
static NS_DEFINE_CID(kTimerManagerCID, NS_TIMERMANAGER_CID);
class nsTimer;
#define NS_PRIORITY_IMMEDIATE 10
void CALLBACK FireTimeout(HWND aWindow,
UINT aMessage,
UINT aTimerID,
DWORD aTime)
{
// Don't allow old timer messages in here.
if(aMessage != WM_TIMER) {
PR_ASSERT(0);
return;
}
nsresult rv;
NS_WITH_SERVICE(nsIWindowsTimerMap, manager, kTimerManagerCID, &rv);
if (NS_FAILED(rv)) return;
nsTimer* timer = manager->GetTimer(aTimerID);
if (timer == nsnull) {
return;
}
if (timer->GetType() != NS_TYPE_REPEATING_PRECISE) {
// stop OS timer: may be restarted later
timer->KillOSTimer();
}
nsCOMPtr<nsITimerQueue> queue = do_QueryInterface(manager, &rv);
if (NS_FAILED(rv)) return;
if (timer->GetPriority() >= NS_PRIORITY_IMMEDIATE) {
// fire timer immediatly
timer->Fire();
} else {
// defer timer firing
queue->AddReadyQueue(timer);
}
// while event queue is empty, fire off waiting timers
MSG wmsg;
while (queue->HasReadyTimers(NS_PRIORITY_LOWEST) &&
!::PeekMessage(&wmsg, NULL, 0, 0, PM_NOREMOVE)) {
queue->FireNextReadyTimer(NS_PRIORITY_LOWEST);
}
}
NS_IMPL_ISUPPORTS1(nsTimer, nsITimer)
nsTimer::nsTimer() : nsITimer()
{
NS_INIT_ISUPPORTS();
mFunc = nsnull;
mCallback = nsnull;
mClosure = nsnull;
mTimerID = 0;
mTimerRunning = false;
}
nsTimer::~nsTimer()
{
KillOSTimer();
NS_IF_RELEASE(mCallback);
}
NS_IMETHODIMP_(void) nsTimer::SetPriority(PRUint32 aPriority)
{
PR_ASSERT(aPriority >= NS_PRIORITY_LOWEST &&
aPriority <= NS_PRIORITY_HIGHEST);
mPriority = aPriority;
}
NS_IMETHODIMP nsTimer::Init(nsTimerCallbackFunc aFunc,
void *aClosure,
PRUint32 aDelay,
PRUint32 aPriority,
PRUint32 aType
)
{
mFunc = aFunc;
mClosure = aClosure;
return Init(aDelay, aPriority, aType);
}
NS_IMETHODIMP nsTimer::Init(nsITimerCallback *aCallback,
PRUint32 aDelay,
PRUint32 aPriority,
PRUint32 aType
)
{
mCallback = aCallback;
NS_ADDREF(mCallback);
return Init(aDelay, aPriority, aType);
}
nsresult nsTimer::Init(PRUint32 aDelay,
PRUint32 aPriority,
PRUint32 aType
)
{
// prevent timer being released before
// it has fired or is canceled
NS_ADDREF_THIS();
mTimerRunning = true;
mDelay = aDelay;
SetPriority(aPriority);
SetType(aType);
StartOSTimer(aDelay);
return NS_OK;
}
void nsTimer::Fire()
{
// prevent a canceled timer which is
// already in ready queue from firing
if (mTimerRunning == false) return;
// prevent notification routine
// from releasing timer by canceling it
NS_ADDREF_THIS();
// invoke notification routine
if (mFunc != nsnull) {
(*mFunc)(this, mClosure);
}
else if (mCallback != nsnull) {
mCallback->Notify(this);
}
if (GetType() == NS_TYPE_REPEATING_SLACK) {
// restart timer
StartOSTimer(GetDelay());
} else if (GetType() == NS_TYPE_ONE_SHOT) {
// timer finished
if (mTimerRunning == true) {
mTimerRunning = false;
NS_RELEASE_THIS();
}
}
NS_RELEASE_THIS();
}
NS_IMETHODIMP_(void) nsTimer::Cancel()
{
KillOSTimer();
// timer finished
if (mTimerRunning == true) {
mTimerRunning = false;
NS_RELEASE_THIS();
}
}
void nsTimer::StartOSTimer(PRUint32 aDelay)
{
PR_ASSERT(mTimerID == 0);
nsresult rv;
NS_WITH_SERVICE(nsIWindowsTimerMap, manager, kTimerManagerCID, &rv);
if (NS_FAILED(rv)) return;
// create OS timer
mTimerID = ::SetTimer(NULL, 0, aDelay, (TIMERPROC)FireTimeout);
// store mapping from OS timer to timer object
manager->AddTimer(mTimerID, this);
}
void nsTimer::KillOSTimer()
{
if (mTimerID != 0) {
nsresult rv;
NS_WITH_SERVICE(nsIWindowsTimerMap, manager, kTimerManagerCID, &rv);
// remove mapping from OS timer to timer object
if (NS_SUCCEEDED(rv)) {
manager->RemoveTimer(mTimerID);
}
// kill OS timer
::KillTimer(NULL, mTimerID);
mTimerID = 0;
}
}