Release 941210
[wine] / windows / timer.c
1 /*
2  * Timer functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 static char Copyright[] = "Copyright  Alexandre Julliard, 1993";
8
9 #include "windows.h"
10 #include "message.h"
11 #include "stddebug.h"
12 /* #define DEBUG_TIMER */
13 #include "debug.h"
14
15
16 typedef struct tagTIMER
17 {
18     HWND             hwnd;
19     WORD             msg;  /* WM_TIMER or WM_SYSTIMER */
20     WORD             id;
21     WORD             timeout;
22     struct tagTIMER *next;
23     DWORD            expires;
24     FARPROC          proc;
25 } TIMER;
26
27 #define NB_TIMERS            34
28 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
29
30 static TIMER TimersArray[NB_TIMERS];
31
32 static TIMER * pNextTimer = NULL;  /* Next timer to expire */
33
34   /* Duration from 'time' until expiration of the timer */
35 #define EXPIRE_TIME(pTimer,time) \
36           (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
37
38
39 /***********************************************************************
40  *           TIMER_InsertTimer
41  *
42  * Insert the timer at its place in the chain.
43  */
44 static void TIMER_InsertTimer( TIMER * pTimer )
45 {
46     if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
47     {
48         pTimer->next = pNextTimer;
49         pNextTimer = pTimer;
50     }
51     else
52     {
53         TIMER * ptr = pNextTimer;       
54         while (ptr->next && (pTimer->expires >= ptr->next->expires))
55             ptr = ptr->next;
56         pTimer->next = ptr->next;
57         ptr->next = pTimer;
58     }
59 }
60
61
62 /***********************************************************************
63  *           TIMER_RemoveTimer
64  *
65  * Remove the timer from the chain.
66  */
67 static void TIMER_RemoveTimer( TIMER * pTimer )
68 {
69     if (pTimer == pNextTimer) pNextTimer = pTimer->next;
70     else
71     {
72         TIMER * ptr = pNextTimer;
73         while (ptr && (ptr->next != pTimer)) ptr = ptr->next;
74         if (ptr) ptr->next = pTimer->next;
75     }
76     pTimer->next = NULL;
77 }
78
79
80 /***********************************************************************
81  *           TIMER_RestartTimers
82  *
83  * Restart an expired timer.
84  */
85 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
86 {
87     TIMER_RemoveTimer( pTimer );
88     pTimer->expires = curTime + pTimer->timeout;
89     TIMER_InsertTimer( pTimer );
90 }
91
92                                
93 /***********************************************************************
94  *           TIMER_CheckTimer
95  *
96  * Check whether a timer has expired, and create a message if necessary.
97  * Otherwise, return time until next timer expiration in 'next'.
98  * If 'hwnd' is not NULL, only consider timers for this window.
99  * If 'remove' is TRUE, remove all expired timers up to the returned one.
100  */
101 BOOL TIMER_CheckTimer( LONG *next, MSG *msg, HWND hwnd, BOOL remove )
102 {
103     TIMER * pTimer = pNextTimer;
104     DWORD curTime = GetTickCount();
105
106     if (hwnd)  /* Find first timer for this window */
107         while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
108
109     if (!pTimer) *next = -1;
110     else *next = EXPIRE_TIME( pTimer, curTime );
111     if (*next != 0) return FALSE;  /* No timer expired */
112
113     if (remove) /* Restart all timers before pTimer, and then pTimer itself */
114     {
115         while (pNextTimer != pTimer) TIMER_RestartTimer( pNextTimer, curTime );
116         TIMER_RestartTimer( pTimer, curTime );
117     }
118
119       /* Build the message */
120     msg->hwnd    = pTimer->hwnd;
121     msg->message = pTimer->msg;
122     msg->wParam  = pTimer->id;
123     msg->lParam  = (LONG)pTimer->proc;
124     msg->time    = curTime;
125     return TRUE;
126 }
127
128
129 /***********************************************************************
130  *           TIMER_SetTimer
131  */
132 static WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout,
133                             FARPROC proc, BOOL sys )
134 {
135     int i;
136     TIMER * pTimer;
137
138     if (!timeout) return 0;
139 /*    if (!hwnd && !proc) return 0; */
140
141       /* Check if there's already a timer with the same hwnd and id */
142
143     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
144         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
145             (pTimer->timeout != 0))
146         {
147               /* Got one: set new values and return */
148             pTimer->timeout = timeout;
149             pTimer->expires = GetTickCount() + timeout;
150             pTimer->proc    = proc;
151             TIMER_RemoveTimer( pTimer );
152             TIMER_InsertTimer( pTimer );
153             return id;
154         }
155
156       /* Find a free timer */
157     
158     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
159         if (!pTimer->timeout) break;
160
161     if (i >= NB_TIMERS) return 0;
162     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return 0;
163     if (!hwnd) id = i + 1;
164     
165       /* Add the timer */
166
167     pTimer->hwnd    = hwnd;
168     pTimer->msg     = sys ? WM_SYSTIMER : WM_TIMER;
169     pTimer->id      = id;
170     pTimer->timeout = timeout;
171     pTimer->expires = GetTickCount() + timeout;
172     pTimer->proc    = proc;
173     TIMER_InsertTimer( pTimer );
174     MSG_IncTimerCount( GetTaskQueue(0) );
175     if (!id)
176         return TRUE;
177     else
178         return id;
179 }
180
181
182 /***********************************************************************
183  *           TIMER_KillTimer
184  */
185 static BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys )
186 {
187     int i;
188     TIMER * pTimer;
189     
190       /* Find the timer */
191     
192     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
193         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
194             (pTimer->timeout != 0)) break;
195     if (i >= NB_TIMERS) return FALSE;
196     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
197     if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
198     else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;    
199
200       /* Delete the timer */
201
202     pTimer->hwnd    = 0;
203     pTimer->msg     = 0;
204     pTimer->id      = 0;
205     pTimer->timeout = 0;
206     pTimer->proc    = 0;
207     TIMER_RemoveTimer( pTimer );
208     MSG_DecTimerCount( GetTaskQueue(0) );
209     return TRUE;
210 }
211
212
213 /***********************************************************************
214  *           SetTimer   (USER.10)
215  */
216 WORD SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc )
217 {
218     dprintf_timer(stddeb, "SetTimer: %d %d %d %p\n", hwnd, id, timeout, proc );
219     return TIMER_SetTimer( hwnd, id, timeout, proc, FALSE );
220 }
221
222
223 /***********************************************************************
224  *           SetSystemTimer   (USER.11)
225  */
226 WORD SetSystemTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc )
227 {
228     dprintf_timer(stddeb, "SetSystemTimer: %d %d %d %p\n", 
229                   hwnd, id, timeout, proc );
230     return TIMER_SetTimer( hwnd, id, timeout, proc, TRUE );
231 }
232
233
234 /***********************************************************************
235  *           KillTimer   (USER.12)
236  */
237 BOOL KillTimer( HWND hwnd, WORD id )
238 {
239     dprintf_timer(stddeb, "KillTimer: %d %d\n", hwnd, id );
240     return TIMER_KillTimer( hwnd, id, FALSE );
241 }
242
243
244 /***********************************************************************
245  *           KillSystemTimer   (USER.182)
246  */
247 BOOL KillSystemTimer( HWND hwnd, WORD id )
248 {
249     dprintf_timer(stddeb, "KillSystemTimer: %d %d\n", hwnd, id );
250     return TIMER_KillTimer( hwnd, id, TRUE );
251 }