Release 980712
[wine/multimedia.git] / multimedia / time.c
blob74266053041c501d7f75afc7dabb71664d3b0a2b
1 /*
2 * MMSYTEM time functions
4 * Copyright 1993 Martin Ayotte
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include "windows.h"
10 #include "win.h"
11 #include "ldt.h"
12 #include "module.h"
13 #include "callback.h"
14 #include "user.h"
15 #include "driver.h"
16 #include "mmsystem.h"
17 #include "debug.h"
18 #include "xmalloc.h"
20 static BOOL32 mmTimeStarted = FALSE;
21 static MMTIME16 mmSysTimeMS;
22 static MMTIME16 mmSysTimeSMPTE;
24 /* this is used to avoid infinite loop in timeGetTime, because
25 of the faked multimedia timers, and will desappear as soon as
26 the timers are implemented correctly.
28 static int time_called=0;
30 typedef struct tagTIMERENTRY {
31 UINT32 wDelay;
32 UINT32 wResol;
33 FARPROC16 lpFunc;
34 HINSTANCE32 hInstance;
35 DWORD dwUser;
36 UINT32 wFlags;
37 UINT32 wTimerID;
38 UINT32 wCurTime;
39 UINT32 iswin32;
40 struct tagTIMERENTRY *Next;
41 DWORD triggertime;
42 } TIMERENTRY, *LPTIMERENTRY;
44 static LPTIMERENTRY lpTimerList = NULL;
47 * FIXME
48 * We're using "1" as the mininum resolution to the timer,
49 * as Windows 95 does, according to the docs. Maybe it should
50 * depend on the computers resources!
52 #define MMSYSTIME_MININTERVAL (1)
53 #define MMSYSTIME_MAXINTERVAL (65535)
56 /**************************************************************************
57 * check_MMtimers
59 static VOID check_MMtimers()
61 LPTIMERENTRY lpTimer = lpTimerList;
62 DWORD curtick = GetTickCount();
64 while (lpTimer != NULL) {
65 if (lpTimer->triggertime <= curtick) {
66 lpTimer->wCurTime = lpTimer->wDelay;
68 if (lpTimer->lpFunc != (FARPROC16) NULL) {
69 TRACE(mmtime, "before CallBack16 !\n");
70 TRACE(mmtime, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
71 lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
72 TRACE(mmtime, "hInstance=%04X !\n", lpTimer->hInstance);
75 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
76 * during interrupt time, is allowed to execute very limited number of API calls (like
77 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
78 * guess current implementation via SetTimer has to be improved upon.
80 if (lpTimer->iswin32)
81 lpTimer->lpFunc(lpTimer->wTimerID,0,lpTimer->dwUser,0,0);
82 else
83 Callbacks->CallTimeFuncProc(lpTimer->lpFunc,
84 lpTimer->wTimerID,0,
85 lpTimer->dwUser,0,0
88 TRACE(mmtime, "after CallBack16 !\n");
90 if (lpTimer->wFlags & TIME_ONESHOT)
91 timeKillEvent32(lpTimer->wTimerID);
93 lpTimer = lpTimer->Next;
97 /**************************************************************************
98 * TIME_MMSysTimeCallback
100 static VOID TIME_MMSysTimeCallback( HWND32 hwnd, UINT32 msg,
101 UINT32 id, DWORD dwTime )
103 LPTIMERENTRY lpTimer = lpTimerList;
104 mmSysTimeMS.u.ms += MMSYSTIME_MININTERVAL;
105 mmSysTimeSMPTE.u.smpte.frame++;
106 while (lpTimer != NULL) {
107 lpTimer->wCurTime--;
108 if (lpTimer->wCurTime == 0) {
109 lpTimer->wCurTime = lpTimer->wDelay;
111 if (lpTimer->lpFunc != (FARPROC16) NULL) {
112 TRACE(mmtime, "before CallBack16 !\n");
113 TRACE(mmtime, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
114 lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
115 TRACE(mmtime, "hInstance=%04X !\n", lpTimer->hInstance);
117 /* This is wrong (lpFunc is NULL all the time)
119 lpFunc = MODULE_GetEntryPoint( lpTimer->hInstance,
120 MODULE_GetOrdinal(lpTimer->hInstance,"TimerCallBack" ));
121 TRACE(mmtime, "lpFunc=%08lx !\n", lpFunc);
125 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
126 * during interrupt time, is allowed to execute very limited number of API calls (like
127 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
128 * guess current implementation via SetTimer has to be improved upon.
130 if (lpTimer->iswin32)
131 lpTimer->lpFunc(lpTimer->wTimerID,0,lpTimer->dwUser,0,0);
132 else
133 Callbacks->CallTimeFuncProc(lpTimer->lpFunc,
134 lpTimer->wTimerID,0,
135 lpTimer->dwUser,0,0
138 TRACE(mmtime, "after CallBack16 !\n");
139 fflush(stdout);
141 if (lpTimer->wFlags & TIME_ONESHOT)
142 timeKillEvent32(lpTimer->wTimerID);
144 lpTimer = lpTimer->Next;
148 /**************************************************************************
149 * StartMMTime [internal]
151 static void StartMMTime()
153 if (!mmTimeStarted) {
154 mmTimeStarted = TRUE;
155 mmSysTimeMS.wType = TIME_MS;
156 mmSysTimeMS.u.ms = 0;
157 mmSysTimeSMPTE.wType = TIME_SMPTE;
158 mmSysTimeSMPTE.u.smpte.hour = 0;
159 mmSysTimeSMPTE.u.smpte.min = 0;
160 mmSysTimeSMPTE.u.smpte.sec = 0;
161 mmSysTimeSMPTE.u.smpte.frame = 0;
162 mmSysTimeSMPTE.u.smpte.fps = 0;
163 mmSysTimeSMPTE.u.smpte.dummy = 0;
164 SetTimer32( 0, 1, MMSYSTIME_MININTERVAL, TIME_MMSysTimeCallback );
168 /**************************************************************************
169 * timeGetSystemTime [WINMM.140]
171 MMRESULT32 WINAPI timeGetSystemTime32(LPMMTIME32 lpTime, UINT32 wSize)
173 TRACE(mmsys, "(%p, %u);\n", lpTime, wSize);
174 if (!mmTimeStarted)
175 StartMMTime();
176 lpTime->wType = TIME_MS;
177 lpTime->u.ms = mmSysTimeMS.u.ms;
178 return 0;
181 /**************************************************************************
182 * timeGetSystemTime [MMSYSTEM.601]
184 MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize)
186 TRACE(mmsys, "(%p, %u);\n", lpTime, wSize);
187 if (!mmTimeStarted)
188 StartMMTime();
189 lpTime->wType = TIME_MS;
190 lpTime->u.ms = mmSysTimeMS.u.ms;
191 return 0;
194 /**************************************************************************
195 * timeSetEvent [MMSYSTEM.602]
197 MMRESULT32 WINAPI timeSetEvent32(UINT32 wDelay,UINT32 wResol,
198 LPTIMECALLBACK32 lpFunc,DWORD dwUser,
199 UINT32 wFlags)
201 WORD wNewID = 0;
202 LPTIMERENTRY lpNewTimer;
203 LPTIMERENTRY lpTimer = lpTimerList;
205 TRACE(mmtime, "(%u, %u, %p, %08lX, %04X);\n",
206 wDelay, wResol, lpFunc, dwUser, wFlags);
207 if (!mmTimeStarted)
208 StartMMTime();
209 lpNewTimer = (LPTIMERENTRY)xmalloc(sizeof(TIMERENTRY));
210 if (lpNewTimer == NULL)
211 return 0;
212 while (lpTimer != NULL) {
213 wNewID = MAX(wNewID, lpTimer->wTimerID);
214 lpTimer = lpTimer->Next;
217 lpNewTimer->Next = lpTimerList;
218 lpTimerList = lpNewTimer;
219 lpNewTimer->wTimerID = wNewID + 1;
220 lpNewTimer->wCurTime = wDelay;
221 lpNewTimer->triggertime = wDelay+GetTickCount();
222 lpNewTimer->wDelay = wDelay;
223 lpNewTimer->wResol = wResol;
224 lpNewTimer->lpFunc = (FARPROC16) lpFunc;
225 lpNewTimer->iswin32 = 1;
226 lpNewTimer->hInstance = GetTaskDS();
227 TRACE(mmtime, "hInstance=%04X !\n", lpNewTimer->hInstance);
228 TRACE(mmtime, "lpFunc=%p !\n",
229 lpFunc);
230 lpNewTimer->dwUser = dwUser;
231 lpNewTimer->wFlags = wFlags;
232 return lpNewTimer->wTimerID;
235 /**************************************************************************
236 * timeSetEvent [MMSYSTEM.602]
238 MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol,
239 LPTIMECALLBACK16 lpFunc,DWORD dwUser,
240 UINT16 wFlags)
242 WORD wNewID = 0;
243 LPTIMERENTRY lpNewTimer;
244 LPTIMERENTRY lpTimer = lpTimerList;
245 TRACE(mmtime, "(%u, %u, %p, %08lX, %04X);\n",
246 wDelay, wResol, lpFunc, dwUser, wFlags);
247 if (!mmTimeStarted)
248 StartMMTime();
249 lpNewTimer = (LPTIMERENTRY)xmalloc(sizeof(TIMERENTRY));
250 if (lpNewTimer == NULL)
251 return 0;
252 while (lpTimer != NULL) {
253 wNewID = MAX(wNewID, lpTimer->wTimerID);
254 lpTimer = lpTimer->Next;
257 lpNewTimer->Next = lpTimerList;
258 lpTimerList = lpNewTimer;
259 lpNewTimer->wTimerID = wNewID + 1;
260 lpNewTimer->wCurTime = wDelay;
261 lpNewTimer->wDelay = wDelay;
262 lpNewTimer->triggertime = wDelay+GetTickCount();
263 lpNewTimer->wResol = wResol;
264 lpNewTimer->lpFunc = (FARPROC16) lpFunc;
265 lpNewTimer->iswin32 = 0;
266 lpNewTimer->hInstance = GetTaskDS();
267 TRACE(mmtime, "hInstance=%04X !\n", lpNewTimer->hInstance);
268 TRACE(mmtime, "(lpFunc)=%p !\n",
269 PTR_SEG_TO_LIN(lpFunc));
270 lpNewTimer->dwUser = dwUser;
271 lpNewTimer->wFlags = wFlags;
272 return lpNewTimer->wTimerID;
275 /**************************************************************************
276 * timeKillEvent [WINMM.142]
278 MMRESULT32 WINAPI timeKillEvent32(UINT32 wID)
280 LPTIMERENTRY xlptimer,*lpTimer = &lpTimerList;
281 while (*lpTimer) {
282 if (wID == (*lpTimer)->wTimerID) {
283 xlptimer = (*lpTimer)->Next;
284 free(*lpTimer);
285 *lpTimer = xlptimer;
286 return TRUE;
288 lpTimer = &((*lpTimer)->Next);
290 return 0;
293 /**************************************************************************
294 * timeKillEvent [MMSYSTEM.603]
296 MMRESULT16 WINAPI timeKillEvent16(UINT16 wID)
298 return timeKillEvent32(wID);
301 /**************************************************************************
302 * timeGetDevCaps [WINMM.139]
304 MMRESULT32 WINAPI timeGetDevCaps32(LPTIMECAPS32 lpCaps,UINT32 wSize)
306 TRACE(mmtime, "(%p, %u) !\n", lpCaps, wSize);
307 if (!mmTimeStarted)
308 StartMMTime();
309 lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL;
310 lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL;
311 return 0;
314 /**************************************************************************
315 * timeGetDevCaps [MMSYSTEM.604]
317 MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize)
319 TRACE(mmtime, "(%p, %u) !\n", lpCaps, wSize);
320 if (!mmTimeStarted)
321 StartMMTime();
322 lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL;
323 lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL;
324 return 0;
327 /**************************************************************************
328 * timeBeginPeriod [WINMM.137]
330 MMRESULT32 WINAPI timeBeginPeriod32(UINT32 wPeriod)
332 TRACE(mmtime, "(%u) !\n", wPeriod);
333 if (!mmTimeStarted)
334 StartMMTime();
335 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
336 return TIMERR_NOCANDO;
337 return 0;
339 /**************************************************************************
340 * timeBeginPeriod [MMSYSTEM.605]
342 MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod)
344 TRACE(mmtime, "(%u) !\n", wPeriod);
345 if (!mmTimeStarted)
346 StartMMTime();
347 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
348 return TIMERR_NOCANDO;
349 return 0;
352 /**************************************************************************
353 * timeEndPeriod [WINMM.138]
355 MMRESULT32 WINAPI timeEndPeriod32(UINT32 wPeriod)
357 TRACE(mmtime, "(%u) !\n", wPeriod);
358 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
359 return TIMERR_NOCANDO;
360 return 0;
363 /**************************************************************************
364 * timeEndPeriod [MMSYSTEM.606]
366 MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod)
368 TRACE(mmtime, "(%u) !\n", wPeriod);
369 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
370 return TIMERR_NOCANDO;
371 return 0;
374 /**************************************************************************
375 * timeGetTime [MMSYSTEM.607][WINMM.141]
377 DWORD WINAPI timeGetTime()
379 /* FIXME all this function should have to be is
380 long result;
381 struct timeval time;
382 TRACE(mmtime,"timeGetTime(); !\n");
383 gettimeofday(&time, 0);
384 result = (((long)time.tv_sec * (long)1000) + ((long)time.tv_usec / (long)1000));
386 but the multimedia timers are not implemented correctly, so all the rest
387 is a workaround to fake them.
390 static DWORD lasttick=0;
391 DWORD newtick;
393 TRACE(mmtime, "!\n");
394 if (!mmTimeStarted)
395 StartMMTime();
396 newtick = GetTickCount();
397 mmSysTimeMS.u.ms+=newtick-lasttick; /* FIXME: faked timer */
398 if (newtick!=lasttick)
400 if (!time_called) { /* to avoid infinite recursion if timeGetTime is called
401 inside check_MMtimers
403 time_called++;
404 check_MMtimers();
405 time_called--;
406 } //check_MMtimers();
407 lasttick = newtick;
408 TRACE(mmtime, "Time = %ld\n",mmSysTimeMS.u.ms);
411 return mmSysTimeMS.u.ms;