Release 940912
[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
12
13 typedef struct tagTIMER
14 {
15     HWND             hwnd;
16     WORD             msg;  /* WM_TIMER or WM_SYSTIMER */
17     WORD             id;
18     WORD             timeout;
19     struct tagTIMER *next;
20     DWORD            expires;
21     FARPROC          proc;
22 } TIMER;
23
24 #define NB_TIMERS            34
25 #define NB_RESERVED_TIMERS    2  /* for SetSystemTimer */
26
27 static TIMER TimersArray[NB_TIMERS];
28
29 static TIMER * pNextTimer = NULL;  /* Next timer to expire */
30
31   /* Duration from 'time' until expiration of the timer */
32 #define EXPIRE_TIME(pTimer,time) \
33           (((pTimer)->expires <= (time)) ? 0 : (pTimer)->expires - (time))
34
35
36 /***********************************************************************
37  *           TIMER_InsertTimer
38  *
39  * Insert the timer at its place in the chain.
40  */
41 static void TIMER_InsertTimer( TIMER * pTimer )
42 {
43     if (!pNextTimer || (pTimer->expires < pNextTimer->expires))
44     {
45         pTimer->next = pNextTimer;
46         pNextTimer = pTimer;
47     }
48     else
49     {
50         TIMER * ptr = pNextTimer;       
51         while (ptr->next && (pTimer->expires >= ptr->next->expires))
52             ptr = ptr->next;
53         pTimer->next = ptr->next;
54         ptr->next = pTimer;
55     }
56 }
57
58
59 /***********************************************************************
60  *           TIMER_RemoveTimer
61  *
62  * Remove the timer from the chain.
63  */
64 static void TIMER_RemoveTimer( TIMER * pTimer )
65 {
66     if (pTimer == pNextTimer) pNextTimer = pTimer->next;
67     else
68     {
69         TIMER * ptr = pNextTimer;
70         while (ptr && (ptr->next != pTimer)) ptr = ptr->next;
71         if (ptr) ptr->next = pTimer->next;
72     }
73     pTimer->next = NULL;
74 }
75
76
77 /***********************************************************************
78  *           TIMER_RestartTimers
79  *
80  * Restart an expired timer.
81  */
82 static void TIMER_RestartTimer( TIMER * pTimer, DWORD curTime )
83 {
84     TIMER_RemoveTimer( pTimer );
85     pTimer->expires = curTime + pTimer->timeout;
86     TIMER_InsertTimer( pTimer );
87 }
88
89                                
90 /***********************************************************************
91  *           TIMER_CheckTimer
92  *
93  * Check whether a timer has expired, and create a message if necessary.
94  * Otherwise, return time until next timer expiration in 'next'.
95  * If 'hwnd' is not NULL, only consider timers for this window.
96  * If 'remove' is TRUE, remove all expired timers up to the returned one.
97  */
98 BOOL TIMER_CheckTimer( LONG *next, MSG *msg, HWND hwnd, BOOL remove )
99 {
100     TIMER * pTimer = pNextTimer;
101     DWORD curTime = GetTickCount();
102
103     if (hwnd)  /* Find first timer for this window */
104         while (pTimer && (pTimer->hwnd != hwnd)) pTimer = pTimer->next;
105
106     if (!pTimer) *next = -1;
107     else *next = EXPIRE_TIME( pTimer, curTime );
108     if (*next != 0) return FALSE;  /* No timer expired */
109
110     if (remove) /* Restart all timers before pTimer, and then pTimer itself */
111     {
112         while (pNextTimer != pTimer) TIMER_RestartTimer( pNextTimer, curTime );
113         TIMER_RestartTimer( pTimer, curTime );
114     }
115
116       /* Build the message */
117     msg->hwnd    = pTimer->hwnd;
118     msg->message = pTimer->msg;
119     msg->wParam  = pTimer->id;
120     msg->lParam  = (LONG)pTimer->proc;
121     msg->time    = curTime;
122     return TRUE;
123 }
124
125
126 /***********************************************************************
127  *           TIMER_SetTimer
128  */
129 static WORD TIMER_SetTimer( HWND hwnd, WORD id, WORD timeout,
130                             FARPROC proc, BOOL sys )
131 {
132     int i;
133     TIMER * pTimer;
134
135     if (!timeout) return 0;
136     if (!hwnd && !proc) return 0;
137
138       /* Check if there's already a timer with the same hwnd and id */
139
140     if (hwnd)
141     {
142         for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
143             if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
144                 (pTimer->timeout != 0))
145             {
146                   /* Got one: set new values and return */
147                 pTimer->timeout = timeout;
148                 pTimer->expires = GetTickCount() + timeout;
149                 pTimer->proc    = proc;
150                 TIMER_RemoveTimer( pTimer );
151                 TIMER_InsertTimer( pTimer );
152                 return id;
153             }
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 #ifdef DEBUG_TIMER    
219     printf( "SetTimer: %d %d %d %p\n", hwnd, id, timeout, proc );
220 #endif
221     return TIMER_SetTimer( hwnd, id, timeout, proc, FALSE );
222 }
223
224
225 /***********************************************************************
226  *           SetSystemTimer   (USER.11)
227  */
228 WORD SetSystemTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc )
229 {
230 #ifdef DEBUG_TIMER    
231     printf( "SetSystemTimer: %d %d %d %p\n", hwnd, id, timeout, proc );
232 #endif
233     return TIMER_SetTimer( hwnd, id, timeout, proc, TRUE );
234 }
235
236
237 /***********************************************************************
238  *           KillTimer   (USER.12)
239  */
240 BOOL KillTimer( HWND hwnd, WORD id )
241 {
242 #ifdef DEBUG_TIMER
243     printf( "KillTimer: %d %d\n", hwnd, id );
244 #endif
245     return TIMER_KillTimer( hwnd, id, FALSE );
246 }
247
248
249 /***********************************************************************
250  *           KillSystemTimer   (USER.182)
251  */
252 BOOL KillSystemTimer( HWND hwnd, WORD id )
253 {
254 #ifdef DEBUG_TIMER
255     printf( "KillSystemTimer: %d %d\n", hwnd, id );
256 #endif
257     return TIMER_KillTimer( hwnd, id, TRUE );
258 }