Release 980503
[wine/hacks.git] / multimedia / time.c
bloba1ae385c30c5c180ce7fc83047a143b0a5515046
1 /*
2 * MMSYTEM time functions
4 * Copyright 1993 Martin Ayotte
5 */
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include "windows.h"
11 #include "win.h"
12 #include "ldt.h"
13 #include "module.h"
14 #include "callback.h"
15 #include "user.h"
16 #include "driver.h"
17 #include "mmsystem.h"
18 #include "debug.h"
19 #include "xmalloc.h"
21 static BOOL32 mmTimeStarted = FALSE;
22 static MMTIME16 mmSysTimeMS;
23 static MMTIME16 mmSysTimeSMPTE;
25 /* this is used to avoid infinite loop in timeGetTime, because
26 of the faked multimedia timers, and will desappear as soon as
27 the timers are implemented correctly.
29 static int time_called=0;
31 typedef struct tagTIMERENTRY {
32 UINT32 wDelay;
33 UINT32 wResol;
34 FARPROC16 lpFunc;
35 HINSTANCE32 hInstance;
36 DWORD dwUser;
37 UINT32 wFlags;
38 UINT32 wTimerID;
39 UINT32 wCurTime;
40 UINT32 iswin32;
41 struct tagTIMERENTRY *Next;
42 DWORD triggertime;
43 } TIMERENTRY, *LPTIMERENTRY;
45 static LPTIMERENTRY lpTimerList = NULL;
48 * FIXME
49 * We're using "1" as the mininum resolution to the timer,
50 * as Windows 95 does, according to the docs. Maybe it should
51 * depend on the computers resources!
53 #define MMSYSTIME_MININTERVAL (1)
54 #define MMSYSTIME_MAXINTERVAL (65535)
57 /**************************************************************************
58 * check_MMtimers
60 static VOID check_MMtimers()
62 LPTIMERENTRY lpTimer = lpTimerList;
63 DWORD curtick = GetTickCount();
65 while (lpTimer != NULL) {
66 if (lpTimer->triggertime <= curtick) {
67 lpTimer->wCurTime = lpTimer->wDelay;
69 if (lpTimer->lpFunc != (FARPROC16) NULL) {
70 TRACE(mmtime, "before CallBack16 !\n");
71 TRACE(mmtime, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
72 lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
73 TRACE(mmtime, "hInstance=%04X !\n", lpTimer->hInstance);
76 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
77 * during interrupt time, is allowed to execute very limited number of API calls (like
78 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
79 * guess current implementation via SetTimer has to be improved upon.
81 if (lpTimer->iswin32)
82 lpTimer->lpFunc(lpTimer->wTimerID,0,lpTimer->dwUser,0,0);
83 else
84 Callbacks->CallTimeFuncProc(lpTimer->lpFunc,
85 lpTimer->wTimerID,0,
86 lpTimer->dwUser,0,0
89 TRACE(mmtime, "after CallBack16 !\n");
91 if (lpTimer->wFlags & TIME_ONESHOT)
92 timeKillEvent32(lpTimer->wTimerID);
94 lpTimer = lpTimer->Next;
98 /**************************************************************************
99 * TIME_MMSysTimeCallback
101 static VOID TIME_MMSysTimeCallback( HWND32 hwnd, UINT32 msg,
102 UINT32 id, DWORD dwTime )
104 LPTIMERENTRY lpTimer = lpTimerList;
105 mmSysTimeMS.u.ms += MMSYSTIME_MININTERVAL;
106 mmSysTimeSMPTE.u.smpte.frame++;
107 while (lpTimer != NULL) {
108 lpTimer->wCurTime--;
109 if (lpTimer->wCurTime == 0) {
110 lpTimer->wCurTime = lpTimer->wDelay;
112 if (lpTimer->lpFunc != (FARPROC16) NULL) {
113 TRACE(mmtime, "before CallBack16 !\n");
114 TRACE(mmtime, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
115 lpTimer->lpFunc, lpTimer->wTimerID, lpTimer->dwUser);
116 TRACE(mmtime, "hInstance=%04X !\n", lpTimer->hInstance);
118 /* This is wrong (lpFunc is NULL all the time)
120 lpFunc = MODULE_GetEntryPoint( lpTimer->hInstance,
121 MODULE_GetOrdinal(lpTimer->hInstance,"TimerCallBack" ));
122 TRACE(mmtime, "lpFunc=%08lx !\n", lpFunc);
126 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
127 * during interrupt time, is allowed to execute very limited number of API calls (like
128 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
129 * guess current implementation via SetTimer has to be improved upon.
131 if (lpTimer->iswin32)
132 lpTimer->lpFunc(lpTimer->wTimerID,0,lpTimer->dwUser,0,0);
133 else
134 Callbacks->CallTimeFuncProc(lpTimer->lpFunc,
135 lpTimer->wTimerID,0,
136 lpTimer->dwUser,0,0
139 TRACE(mmtime, "after CallBack16 !\n");
140 fflush(stdout);
142 if (lpTimer->wFlags & TIME_ONESHOT)
143 timeKillEvent32(lpTimer->wTimerID);
145 lpTimer = lpTimer->Next;
149 /**************************************************************************
150 * StartMMTime [internal]
152 static void StartMMTime()
154 if (!mmTimeStarted) {
155 mmTimeStarted = TRUE;
156 mmSysTimeMS.wType = TIME_MS;
157 mmSysTimeMS.u.ms = 0;
158 mmSysTimeSMPTE.wType = TIME_SMPTE;
159 mmSysTimeSMPTE.u.smpte.hour = 0;
160 mmSysTimeSMPTE.u.smpte.min = 0;
161 mmSysTimeSMPTE.u.smpte.sec = 0;
162 mmSysTimeSMPTE.u.smpte.frame = 0;
163 mmSysTimeSMPTE.u.smpte.fps = 0;
164 mmSysTimeSMPTE.u.smpte.dummy = 0;
165 SetTimer32( 0, 1, MMSYSTIME_MININTERVAL, TIME_MMSysTimeCallback );
169 /**************************************************************************
170 * timeGetSystemTime [WINMM.140]
172 MMRESULT32 WINAPI timeGetSystemTime32(LPMMTIME32 lpTime, UINT32 wSize)
174 TRACE(mmsys, "(%p, %u);\n", lpTime, wSize);
175 if (!mmTimeStarted)
176 StartMMTime();
177 lpTime->wType = TIME_MS;
178 lpTime->u.ms = mmSysTimeMS.u.ms;
179 return 0;
182 /**************************************************************************
183 * timeGetSystemTime [MMSYSTEM.601]
185 MMRESULT16 WINAPI timeGetSystemTime16(LPMMTIME16 lpTime, UINT16 wSize)
187 TRACE(mmsys, "(%p, %u);\n", lpTime, wSize);
188 if (!mmTimeStarted)
189 StartMMTime();
190 lpTime->wType = TIME_MS;
191 lpTime->u.ms = mmSysTimeMS.u.ms;
192 return 0;
195 /**************************************************************************
196 * timeSetEvent [MMSYSTEM.602]
198 MMRESULT32 WINAPI timeSetEvent32(UINT32 wDelay,UINT32 wResol,
199 LPTIMECALLBACK32 lpFunc,DWORD dwUser,
200 UINT32 wFlags)
202 WORD wNewID = 0;
203 LPTIMERENTRY lpNewTimer;
204 LPTIMERENTRY lpTimer = lpTimerList;
206 TRACE(mmtime, "(%u, %u, %p, %08lX, %04X);\n",
207 wDelay, wResol, lpFunc, dwUser, wFlags);
208 if (!mmTimeStarted)
209 StartMMTime();
210 lpNewTimer = (LPTIMERENTRY)xmalloc(sizeof(TIMERENTRY));
211 if (lpNewTimer == NULL)
212 return 0;
213 while (lpTimer != NULL) {
214 wNewID = MAX(wNewID, lpTimer->wTimerID);
215 lpTimer = lpTimer->Next;
218 lpNewTimer->Next = lpTimerList;
219 lpTimerList = lpNewTimer;
220 lpNewTimer->wTimerID = wNewID + 1;
221 lpNewTimer->wCurTime = wDelay;
222 lpNewTimer->triggertime = wDelay+GetTickCount();
223 lpNewTimer->wDelay = wDelay;
224 lpNewTimer->wResol = wResol;
225 lpNewTimer->lpFunc = (FARPROC16) lpFunc;
226 lpNewTimer->iswin32 = 1;
227 lpNewTimer->hInstance = GetTaskDS();
228 TRACE(mmtime, "hInstance=%04X !\n", lpNewTimer->hInstance);
229 TRACE(mmtime, "lpFunc=%p !\n",
230 lpFunc);
231 lpNewTimer->dwUser = dwUser;
232 lpNewTimer->wFlags = wFlags;
233 return lpNewTimer->wTimerID;
236 /**************************************************************************
237 * timeSetEvent [MMSYSTEM.602]
239 MMRESULT16 WINAPI timeSetEvent16(UINT16 wDelay, UINT16 wResol,
240 LPTIMECALLBACK16 lpFunc,DWORD dwUser,
241 UINT16 wFlags)
243 WORD wNewID = 0;
244 LPTIMERENTRY lpNewTimer;
245 LPTIMERENTRY lpTimer = lpTimerList;
246 TRACE(mmtime, "(%u, %u, %p, %08lX, %04X);\n",
247 wDelay, wResol, lpFunc, dwUser, wFlags);
248 if (!mmTimeStarted)
249 StartMMTime();
250 lpNewTimer = (LPTIMERENTRY)xmalloc(sizeof(TIMERENTRY));
251 if (lpNewTimer == NULL)
252 return 0;
253 while (lpTimer != NULL) {
254 wNewID = MAX(wNewID, lpTimer->wTimerID);
255 lpTimer = lpTimer->Next;
258 lpNewTimer->Next = lpTimerList;
259 lpTimerList = lpNewTimer;
260 lpNewTimer->wTimerID = wNewID + 1;
261 lpNewTimer->wCurTime = wDelay;
262 lpNewTimer->wDelay = wDelay;
263 lpNewTimer->triggertime = wDelay+GetTickCount();
264 lpNewTimer->wResol = wResol;
265 lpNewTimer->lpFunc = (FARPROC16) lpFunc;
266 lpNewTimer->iswin32 = 0;
267 lpNewTimer->hInstance = GetTaskDS();
268 TRACE(mmtime, "hInstance=%04X !\n", lpNewTimer->hInstance);
269 TRACE(mmtime, "(lpFunc)=%p !\n",
270 PTR_SEG_TO_LIN(lpFunc));
271 lpNewTimer->dwUser = dwUser;
272 lpNewTimer->wFlags = wFlags;
273 return lpNewTimer->wTimerID;
276 /**************************************************************************
277 * timeKillEvent [WINMM.142]
279 MMRESULT32 WINAPI timeKillEvent32(UINT32 wID)
281 LPTIMERENTRY xlptimer,*lpTimer = &lpTimerList;
282 while (*lpTimer) {
283 if (wID == (*lpTimer)->wTimerID) {
284 xlptimer = (*lpTimer)->Next;
285 free(*lpTimer);
286 *lpTimer = xlptimer;
287 return TRUE;
289 lpTimer = &((*lpTimer)->Next);
291 return 0;
294 /**************************************************************************
295 * timeKillEvent [MMSYSTEM.603]
297 MMRESULT16 WINAPI timeKillEvent16(UINT16 wID)
299 return timeKillEvent32(wID);
302 /**************************************************************************
303 * timeGetDevCaps [WINMM.139]
305 MMRESULT32 WINAPI timeGetDevCaps32(LPTIMECAPS32 lpCaps,UINT32 wSize)
307 TRACE(mmtime, "(%p, %u) !\n", lpCaps, wSize);
308 if (!mmTimeStarted)
309 StartMMTime();
310 lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL;
311 lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL;
312 return 0;
315 /**************************************************************************
316 * timeGetDevCaps [MMSYSTEM.604]
318 MMRESULT16 WINAPI timeGetDevCaps16(LPTIMECAPS16 lpCaps, UINT16 wSize)
320 TRACE(mmtime, "(%p, %u) !\n", lpCaps, wSize);
321 if (!mmTimeStarted)
322 StartMMTime();
323 lpCaps->wPeriodMin = MMSYSTIME_MININTERVAL;
324 lpCaps->wPeriodMax = MMSYSTIME_MAXINTERVAL;
325 return 0;
328 /**************************************************************************
329 * timeBeginPeriod [WINMM.137]
331 MMRESULT32 WINAPI timeBeginPeriod32(UINT32 wPeriod)
333 TRACE(mmtime, "(%u) !\n", wPeriod);
334 if (!mmTimeStarted)
335 StartMMTime();
336 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
337 return TIMERR_NOCANDO;
338 return 0;
340 /**************************************************************************
341 * timeBeginPeriod [MMSYSTEM.605]
343 MMRESULT16 WINAPI timeBeginPeriod16(UINT16 wPeriod)
345 TRACE(mmtime, "(%u) !\n", wPeriod);
346 if (!mmTimeStarted)
347 StartMMTime();
348 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
349 return TIMERR_NOCANDO;
350 return 0;
353 /**************************************************************************
354 * timeEndPeriod [WINMM.138]
356 MMRESULT32 WINAPI timeEndPeriod32(UINT32 wPeriod)
358 TRACE(mmtime, "(%u) !\n", wPeriod);
359 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
360 return TIMERR_NOCANDO;
361 return 0;
364 /**************************************************************************
365 * timeEndPeriod [MMSYSTEM.606]
367 MMRESULT16 WINAPI timeEndPeriod16(UINT16 wPeriod)
369 TRACE(mmtime, "(%u) !\n", wPeriod);
370 if (wPeriod < MMSYSTIME_MININTERVAL || wPeriod > MMSYSTIME_MAXINTERVAL)
371 return TIMERR_NOCANDO;
372 return 0;
375 /**************************************************************************
376 * timeGetTime [MMSYSTEM.607][WINMM.141]
378 DWORD WINAPI timeGetTime()
380 /* FIXME all this function should have to be is
381 long result;
382 struct timeval time;
383 TRACE(mmtime,"timeGetTime(); !\n");
384 gettimeofday(&time, 0);
385 result = (((long)time.tv_sec * (long)1000) + ((long)time.tv_usec / (long)1000));
387 but the multimedia timers are not implemented correctly, so all the rest
388 is a workaround to fake them.
391 static DWORD lasttick=0;
392 DWORD newtick;
394 TRACE(mmtime, "!\n");
395 if (!mmTimeStarted)
396 StartMMTime();
397 newtick = GetTickCount();
398 mmSysTimeMS.u.ms+=newtick-lasttick; /* FIXME: faked timer */
399 if (newtick!=lasttick)
401 if (!time_called) { /* to avoid infinite recursion if timeGetTime is called
402 inside check_MMtimers
404 time_called++;
405 check_MMtimers();
406 time_called--;
407 } //check_MMtimers();
408 lasttick = newtick;
409 TRACE(mmtime, "Time = %ld\n",mmSysTimeMS.u.ms);
412 return mmSysTimeMS.u.ms;