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