Release 951003
[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     dprintf_timer(stddeb, "Timer expired: %p, "NPFMT", %04x, %04x, %08lx\n", 
118                   pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
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     dprintf_timer(stddeb, "Timer added: %p, "NPFMT", %04x, %04x, %08lx\n", 
174                   pTimer, pTimer->hwnd, pTimer->msg, pTimer->id, (DWORD)pTimer->proc);
175     TIMER_InsertTimer( pTimer );
176     MSG_IncTimerCount( GetTaskQueue(0) );
177     if (!id)
178         return TRUE;
179     else
180         return id;
181 }
182
183
184 /***********************************************************************
185  *           TIMER_KillTimer
186  */
187 static BOOL TIMER_KillTimer( HWND hwnd, WORD id, BOOL sys )
188 {
189     int i;
190     TIMER * pTimer;
191     
192       /* Find the timer */
193     
194     for (i = 0, pTimer = TimersArray; i < NB_TIMERS; i++, pTimer++)
195         if ((pTimer->hwnd == hwnd) && (pTimer->id == id) &&
196             (pTimer->timeout != 0)) break;
197     if (i >= NB_TIMERS) return FALSE;
198     if (!sys && (i >= NB_TIMERS-NB_RESERVED_TIMERS)) return FALSE;
199     if (!sys && (pTimer->msg != WM_TIMER)) return FALSE;
200     else if (sys && (pTimer->msg != WM_SYSTIMER)) return FALSE;    
201
202       /* Delete the timer */
203
204     pTimer->hwnd    = 0;
205     pTimer->msg     = 0;
206     pTimer->id      = 0;
207     pTimer->timeout = 0;
208     pTimer->proc    = 0;
209     TIMER_RemoveTimer( pTimer );
210     MSG_DecTimerCount( GetTaskQueue(0) );
211     return TRUE;
212 }
213
214
215 /***********************************************************************
216  *           SetTimer   (USER.10)
217  */
218 WORD SetTimer( HWND hwnd, WORD id, WORD timeout, FARPROC proc )
219 {
220     dprintf_timer(stddeb, "SetTimer: "NPFMT" %d %d %08lx\n", hwnd, id, timeout, (LONG)proc );
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     dprintf_timer(stddeb, "SetSystemTimer: "NPFMT" %d %d %08lx\n", 
231                   hwnd, id, timeout, (LONG)proc );
232     return TIMER_SetTimer( hwnd, id, timeout, proc, TRUE );
233 }
234
235
236 /***********************************************************************
237  *           KillTimer   (USER.12)
238  */
239 BOOL KillTimer( HWND hwnd, WORD id )
240 {
241     dprintf_timer(stddeb, "KillTimer: "NPFMT" %d\n", hwnd, id );
242     return TIMER_KillTimer( hwnd, id, FALSE );
243 }
244
245
246 /***********************************************************************
247  *           KillSystemTimer   (USER.182)
248  */
249 BOOL KillSystemTimer( HWND hwnd, WORD id )
250 {
251     dprintf_timer(stddeb, "KillSystemTimer: "NPFMT" %d\n", hwnd, id );
252     return TIMER_KillTimer( hwnd, id, TRUE );
253 }