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