blob: b08e892399820d53d4c947cf5baf915dc8d2d68d [file] [log] [blame]
/*
* Timer functions
*
* Copyright 1993 Alexandre Julliard
*/
#include "windows.h"
#include "queue.h"
#include "winproc.h"
#include "stddebug.h"
/* #define DEBUG_TIMER */
#include "debug.h"
typedef struct tagTIMER
{
HWND32 hwnd;
HQUEUE16 hq;
UINT16 msg; /* WM_TIMER or WM_SYSTIMER */
UINT32 id;
UINT32 timeout;
struct tagTIMER *next;
DWORD expires; /* Next expiration, or 0 if already expired */
HWINDOWPROC proc;
} TIMER;
#define NB_TIMERS 34
#define NB_RESERVED_TIMERS 2 /* for SetSystemTimer */
static TIMER TimersArray[NB_TIMERS];
static TIMER * pNextTimer = NULL; /* Next timer to expire */
/* Duration from 'time' until expiration of the timer */
#define EXPIRE_TIME(pTimer,time) \
(((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
/***********************************************************************
* TIMER_InsertTimer
*
* Insert the timer at its place in the chain.
*/
static void TIMER_InsertTimer( TIMER * pTimer )
{
if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
{
pTimer->next = pNextTimer;
pNextTimer = pTimer;
}
else
{
TIMER * ptr = pNextTimer;
while (ptr->next && (pTimer->expires >= ptr->next->expires))
ptr = ptr->next;
pTimer->next = ptr->next;
ptr->next = pTimer;
}
}
/***********************************************************************
* TIMER_RemoveTimer
*
* Remove the timer from the chain.
*/
static void TIMER_RemoveTimer( TIMER * pTimer )
{
TIMER **ppTimer = &pNextTimer;
while (*ppTimer && (*ppTimer != pTimer)) ppTimer = &(*ppTimer)->next;
if (*ppTimer) *ppTimer = pTimer->next;
pTimer->next = NULL;
if (!pTimer->expires) QUEUE_DecTimerCount( pTimer->hq );
}
/***********************************************************************
* TIMER_ClearTimer
*
* Clear and remove a timer.
*/
static void TIMER_ClearTimer( TIMER * pTimer )
{
TIMER_RemoveTimer( pTimer );
pTimer->hwnd = 0;
pTimer->msg = 0;
pTimer->id = 0;
pTimer->timeout = 0;
WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
}
/***********************************************************************
* TIMER_SwitchQueue
*/
void TIMER_SwitchQueue( HQUEUE16 old, HQUEUE16 new )
{
TIMER * pT = pNextTimer;
while (pT)
{
if (pT->hq == old) pT->hq = new;
pT = pT->next;
}
}
/***********************************************************************
* TIMER_RemoveWindowTimers
*
* Remove all timers for a given window.
*/
void TIMER_RemoveWindowTimers( HWND32 hwnd )
{
int i;
TIMER *pTimer;
for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
if ((pTimer->hwnd == hwnd) && pTimer->timeout)
TIMER_ClearTimer( pTimer );
}
/***********************************************************************
* TIMER_RemoveQueueTimers
*
* Remove all timers for a given queue.
*/
void TIMER_RemoveQueueTimers( HQUEUE16 hqueue )
{
int i;
TIMER *pTimer;
for (i = NB_TIMERS, pTimer = TimersArray; i > 0; i--, pTimer++)
if ((pTimer->hq == hqueue) && pTimer->timeout)
TIMER_ClearTimer( pTimer );
}
/***********************************************************************
* TIMER_RestartTimers
*
* Restart an expired timer.
*/
static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
{
TIMER_RemoveTimer( pTimer );
pTimer->expires = curTime + pTimer->timeout;
TIMER_InsertTimer( pTimer );
}
/***********************************************************************
* TIMER_GetNextExpiration
*
* Return next timer expiration time, or -1 if none.
*/
LONG TIMER_GetNextExpiration(void)
{
return pNextTimer ? EXPIRE_TIME( pNextTimer, GetTickCount() ) : -1;
}
/***********************************************************************
* TIMER_ExpireTimers
*
* Mark expired timers and wake the appropriate queues.
*/
void TIMER_ExpireTimers(void)
{
TIMER *pTimer = pNextTimer;
DWORD curTime = GetTickCount();
while (pTimer && !pTimer->expires) /* Skip already expired timers */
pTimer = pTimer->next;
while (pTimer && (pTimer->expires <= curTime))
{
pTimer->expires = 0;
QUEUE_IncTimerCount( pTimer->hq );
pTimer = pTimer->next;
}
}
/***********************************************************************
* TIMER_GetTimerMsg
*
* Build a message for an expired timer.
*/
BOOL32 TIMER_GetTimerMsg( MSG16 *msg, HWND32 hwnd,
HQUEUE16 hQueue, BOOL32 remove )
{
TIMER *pTimer = pNextTimer;
DWORD curTime = GetTickCount();
if (hwnd) /* Find first timer for this window */
while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
else /* Find first timer for this queue */
while (pTimer && (pTimer->hq != hQueue)) pTimer = pTimer->next;
if (!pTimer || (pTimer->expires > curTime)) return FALSE; /* No timer */
if (remove) TIMER_RestartTimer( pTimer, curTime ); /* Restart it */
dprintf_timer( stddeb, "Timer expired: %04x, %04x, %04x, %08lx\n",
pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
/* Build the message */
msg->hwnd = (HWND16)pTimer->hwnd;
msg->message = pTimer->msg;
msg->wParam = (UINT16)pTimer->id;
msg->lParam = (LONG)pTimer->proc;
msg->time = curTime;
return TRUE;
}
/***********************************************************************
* TIMER_SetTimer
*/
static UINT32 TIMER_SetTimer( HWND32 hwnd, UINT32 id, UINT32 timeout,
WNDPROC16 proc, WINDOWPROCTYPE type, BOOL32 sys )
{
int i;
TIMER * pTimer;
if (!timeout) return 0;
/* Check if there's already a timer with the same hwnd and id */
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
(pTimer->timeout != 0))
{
/* Got one: set new values and return */
TIMER_RemoveTimer( pTimer );
pTimer->timeout = timeout;
WINPROC_FreeProc( pTimer->proc, WIN_PROC_TIMER );
pTimer->proc = (HWINDOWPROC)0;
if (proc) WINPROC_SetProc( &pTimer->proc, proc,
type, WIN_PROC_TIMER );
pTimer->expires = GetTickCount() + timeout;
TIMER_InsertTimer( pTimer );
return id;
}
/* Find a free timer */
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if (!pTimer->timeout) break;
if (i >= NB_TIMERS) return 0;
if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
if (!hwnd) id = i + 1;
/* Add the timer */
pTimer->hwnd = hwnd;
pTimer->hq = (hwnd) ? GetTaskQueue( GetWindowTask16( hwnd ) )
: GetTaskQueue( 0 );
pTimer->msg = sys ? WM_SYSTIMER : WM_TIMER;
pTimer->id = id;
pTimer->timeout = timeout;
pTimer->expires = GetTickCount() + timeout;
pTimer->proc = (HWINDOWPROC)0;
if (proc) WINPROC_SetProc( &pTimer->proc, proc, type, WIN_PROC_TIMER );
dprintf_timer( stddeb, "Timer added: %p, %04x, %04x, %04x, %08lx\n",
pTimer, pTimer->hwnd, pTimer->msg, pTimer->id,
(DWORD)pTimer->proc );
TIMER_InsertTimer( pTimer );
if (!id) return TRUE;
else return id;
}
/***********************************************************************
* TIMER_KillTimer
*/
static BOOL32 TIMER_KillTimer( HWND32 hwnd, UINT32 id, BOOL32 sys )
{
int i;
TIMER * pTimer;
/* Find the timer */
for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
(pTimer->timeout != 0)) break;
if (i >= NB_TIMERS) return FALSE;
if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;
/* Delete the timer */
TIMER_ClearTimer( pTimer );
return TRUE;
}
/***********************************************************************
* SetTimer16 (USER.10)
*/
UINT16 SetTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout, TIMERPROC16 proc )
{
dprintf_timer( stddeb, "SetTimer16: %04x %d %d %08lx\n",
hwnd, id, timeout, (LONG)proc );
return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
WIN_PROC_16, FALSE );
}
/***********************************************************************
* SetTimer32 (USER32.510)
*/
UINT32 SetTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout, TIMERPROC32 proc )
{
dprintf_timer( stddeb, "SetTimer32: %04x %d %d %08lx\n",
hwnd, id, timeout, (LONG)proc );
return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
WIN_PROC_32A, FALSE );
}
/***********************************************************************
* SetSystemTimer16 (USER.11)
*/
UINT16 SetSystemTimer16( HWND16 hwnd, UINT16 id, UINT16 timeout,
TIMERPROC16 proc )
{
dprintf_timer( stddeb, "SetSystemTimer16: %04x %d %d %08lx\n",
hwnd, id, timeout, (LONG)proc );
return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
WIN_PROC_16, TRUE );
}
/***********************************************************************
* SetSystemTimer32 (USER32.508)
*/
UINT32 SetSystemTimer32( HWND32 hwnd, UINT32 id, UINT32 timeout,
TIMERPROC32 proc )
{
dprintf_timer( stddeb, "SetSystemTimer32: %04x %d %d %08lx\n",
hwnd, id, timeout, (LONG)proc );
return TIMER_SetTimer( hwnd, id, timeout, (WNDPROC16)proc,
WIN_PROC_32A, TRUE );
}
/***********************************************************************
* KillTimer16 (USER.12)
*/
BOOL16 KillTimer16( HWND16 hwnd, UINT16 id )
{
dprintf_timer(stddeb, "KillTimer16: %04x %d\n", hwnd, id );
return TIMER_KillTimer( hwnd, id, FALSE );
}
/***********************************************************************
* KillTimer32 (USER32.353)
*/
BOOL32 KillTimer32( HWND32 hwnd, UINT32 id )
{
dprintf_timer(stddeb, "KillTimer32: %04x %d\n", hwnd, id );
return TIMER_KillTimer( hwnd, id, FALSE );
}
/***********************************************************************
* KillSystemTimer16 (USER.182)
*/
BOOL16 KillSystemTimer16( HWND16 hwnd, UINT16 id )
{
dprintf_timer( stddeb, "KillSystemTimer16: %04x %d\n", hwnd, id );
return TIMER_KillTimer( hwnd, id, TRUE );
}
/***********************************************************************
* KillSystemTimer32 (USER32.352)
*/
BOOL32 KillSystemTimer32( HWND32 hwnd, UINT32 id )
{
dprintf_timer( stddeb, "KillSystemTimer32: %04x %d\n", hwnd, id );
return TIMER_KillTimer( hwnd, id, TRUE );
}