1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * MMSYTEM time functions
6 * Copyright 1993 Martin Ayotte
13 #include "wine/winbase16.h" /* GetTaskDS */
18 #include "debugtools.h"
20 DECLARE_DEBUG_CHANNEL(mmsys
)
21 DECLARE_DEBUG_CHANNEL(mmtime
)
23 #define USE_FAKE_MM_TIMERS
25 static MMTIME16 mmSysTimeMS
;
26 static MMTIME16 mmSysTimeSMPTE
;
28 typedef struct tagTIMERENTRY
{
38 struct tagTIMERENTRY
* Next
;
39 } TIMERENTRY
, *LPTIMERENTRY
;
41 static LPTIMERENTRY lpTimerList
= NULL
;
43 #ifdef USE_FAKE_MM_TIMERS
44 static DWORD dwLastCBTick
= 0;
45 static BOOL bUseFakeTimers
= FALSE
;
46 static WORD wInCallBackLoop
= 0;
51 * We're using "1" as the mininum resolution to the timer,
52 * as Windows 95 does, according to the docs. Maybe it should
53 * depend on the computers resources!
55 #define MMSYSTIME_MININTERVAL (1)
56 #define MMSYSTIME_MAXINTERVAL (65535)
58 static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer
, DWORD dwCurrent
)
60 lpTimer
->wCurTime
= lpTimer
->wDelay
;
62 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
63 TRACE_(mmtime
)("before CallBack16 (%lu)!\n", dwCurrent
);
64 TRACE_(mmtime
)("lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
65 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
66 TRACE_(mmtime
)("hInstance=%04X !\n", lpTimer
->hInstance
);
69 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
70 * during interrupt time, is allowed to execute very limited number of API calls (like
71 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
72 * guess current implementation via SetTimer has to be improved upon.
74 switch (lpTimer
->wFlags
& 0x30) {
75 case TIME_CALLBACK_FUNCTION
:
77 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
79 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
83 case TIME_CALLBACK_EVENT_SET
:
84 SetEvent((HANDLE
)lpTimer
->lpFunc
);
86 case TIME_CALLBACK_EVENT_PULSE
:
87 PulseEvent((HANDLE
)lpTimer
->lpFunc
);
90 FIXME_(mmtime
)("Unknown callback type 0x%04x for mmtime callback (%p),ignored.\n",lpTimer
->wFlags
,lpTimer
->lpFunc
);
93 TRACE_(mmtime
)("after CallBack16 !\n");
95 if (lpTimer
->wFlags
& TIME_ONESHOT
)
96 timeKillEvent(lpTimer
->wTimerID
);
99 /**************************************************************************
100 * TIME_MMSysTimeCallback
102 static VOID WINAPI
TIME_MMSysTimeCallback( HWND hwnd
, UINT msg
,
103 UINT id
, DWORD dwTime
)
105 LPTIMERENTRY lpTimer
;
107 mmSysTimeMS
.u
.ms
+= MMSYSTIME_MININTERVAL
;
108 mmSysTimeSMPTE
.u
.smpte
.frame
++;
110 #ifdef USE_FAKE_MM_TIMERS
112 dwLastCBTick
= GetTickCount();
114 if (!wInCallBackLoop
++)
116 for (lpTimer
= lpTimerList
; lpTimer
!= NULL
; lpTimer
= lpTimer
->Next
) {
117 if (lpTimer
->wCurTime
< MMSYSTIME_MININTERVAL
) {
118 TIME_TriggerCallBack(lpTimer
, dwTime
);
120 lpTimer
->wCurTime
-= MMSYSTIME_MININTERVAL
;
123 #ifdef USE_FAKE_MM_TIMERS
128 /**************************************************************************
129 * StartMMTime [internal]
131 static void StartMMTime()
133 static BOOL mmTimeStarted
= FALSE
;
135 if (!mmTimeStarted
) {
136 mmTimeStarted
= TRUE
;
137 mmSysTimeMS
.wType
= TIME_MS
;
138 mmSysTimeMS
.u
.ms
= 0;
139 mmSysTimeSMPTE
.wType
= TIME_SMPTE
;
140 mmSysTimeSMPTE
.u
.smpte
.hour
= 0;
141 mmSysTimeSMPTE
.u
.smpte
.min
= 0;
142 mmSysTimeSMPTE
.u
.smpte
.sec
= 0;
143 mmSysTimeSMPTE
.u
.smpte
.frame
= 0;
144 mmSysTimeSMPTE
.u
.smpte
.fps
= 0;
145 mmSysTimeSMPTE
.u
.smpte
.dummy
= 0;
146 SetTimer( 0, 0, MMSYSTIME_MININTERVAL
, TIME_MMSysTimeCallback
);
147 #ifdef USE_FAKE_MM_TIMERS
148 bUseFakeTimers
= PROFILE_GetWineIniBool("options", "MMFakeTimers", TRUE
);
149 TRACE_(mmtime
)("FakeTimer=%c\n", bUseFakeTimers
? 'Y' : 'N');
151 dwLastCBTick
= GetTickCount();
156 /**************************************************************************
157 * timeGetSystemTime [WINMM.140]
159 MMRESULT WINAPI
timeGetSystemTime(LPMMTIME lpTime
, UINT wSize
)
161 TRACE_(mmsys
)("(%p, %u);\n", lpTime
, wSize
);
163 lpTime
->wType
= TIME_MS
;
164 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
168 /**************************************************************************
169 * timeGetSystemTime [MMSYSTEM.601]
171 MMRESULT16 WINAPI
timeGetSystemTime16(LPMMTIME16 lpTime
, UINT16 wSize
)
173 TRACE_(mmsys
)("(%p, %u);\n", lpTime
, wSize
);
175 lpTime
->wType
= TIME_MS
;
176 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
180 static WORD
timeSetEventInternal(UINT wDelay
,UINT wResol
,
181 FARPROC16 lpFunc
,DWORD dwUser
,
182 UINT wFlags
, UINT16 isWin32
)
185 LPTIMERENTRY lpNewTimer
;
186 LPTIMERENTRY lpTimer
= lpTimerList
;
188 TRACE_(mmtime
)("(%u, %u, %p, %08lX, %04X);\n",
189 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
191 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
192 if (lpNewTimer
== NULL
)
194 while (lpTimer
!= NULL
) {
195 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
196 lpTimer
= lpTimer
->Next
;
199 lpNewTimer
->Next
= lpTimerList
;
200 lpTimerList
= lpNewTimer
;
201 lpNewTimer
->wTimerID
= wNewID
+ 1;
202 lpNewTimer
->wCurTime
= wDelay
;
203 lpNewTimer
->wDelay
= wDelay
;
204 lpNewTimer
->wResol
= wResol
;
205 lpNewTimer
->lpFunc
= lpFunc
;
206 lpNewTimer
->isWin32
= isWin32
;
207 lpNewTimer
->hInstance
= GetTaskDS16();
208 TRACE_(mmtime
)("hInstance=%04X !\n", lpNewTimer
->hInstance
);
209 TRACE_(mmtime
)("lpFunc=0x%08lx !\n", (DWORD
)lpFunc
);
210 lpNewTimer
->dwUser
= dwUser
;
211 lpNewTimer
->wFlags
= wFlags
;
212 return lpNewTimer
->wTimerID
;
215 /**************************************************************************
216 * timeSetEvent [MMSYSTEM.602]
218 MMRESULT WINAPI
timeSetEvent(UINT wDelay
,UINT wResol
,
219 LPTIMECALLBACK lpFunc
,DWORD dwUser
,
222 return timeSetEventInternal(wDelay
, wResol
, (FARPROC16
)lpFunc
,
226 /**************************************************************************
227 * timeSetEvent [MMSYSTEM.602]
229 MMRESULT16 WINAPI
timeSetEvent16(UINT16 wDelay
, UINT16 wResol
,
230 LPTIMECALLBACK16 lpFunc
,DWORD dwUser
,
233 return timeSetEventInternal(wDelay
, wResol
, (FARPROC16
)lpFunc
,
237 /**************************************************************************
238 * timeKillEvent [WINMM.142]
240 MMRESULT WINAPI
timeKillEvent(UINT wID
)
242 LPTIMERENTRY
* lpTimer
;
244 for (lpTimer
= &lpTimerList
; *lpTimer
; lpTimer
= &((*lpTimer
)->Next
)) {
245 if (wID
== (*lpTimer
)->wTimerID
) {
246 LPTIMERENTRY xlptimer
= (*lpTimer
)->Next
;
256 /**************************************************************************
257 * timeKillEvent [MMSYSTEM.603]
259 MMRESULT16 WINAPI
timeKillEvent16(UINT16 wID
)
261 return timeKillEvent(wID
);
264 /**************************************************************************
265 * timeGetDevCaps [WINMM.139]
267 MMRESULT WINAPI
timeGetDevCaps(LPTIMECAPS lpCaps
,UINT wSize
)
269 TRACE_(mmtime
)("(%p, %u) !\n", lpCaps
, wSize
);
271 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
272 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
276 /**************************************************************************
277 * timeGetDevCaps [MMSYSTEM.604]
279 MMRESULT16 WINAPI
timeGetDevCaps16(LPTIMECAPS16 lpCaps
, UINT16 wSize
)
281 TRACE_(mmtime
)("(%p, %u) !\n", lpCaps
, wSize
);
283 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
284 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
288 /**************************************************************************
289 * timeBeginPeriod [WINMM.137]
291 MMRESULT WINAPI
timeBeginPeriod(UINT wPeriod
)
293 TRACE_(mmtime
)("(%u) !\n", wPeriod
);
295 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
296 return TIMERR_NOCANDO
;
299 /**************************************************************************
300 * timeBeginPeriod [MMSYSTEM.605]
302 MMRESULT16 WINAPI
timeBeginPeriod16(UINT16 wPeriod
)
304 TRACE_(mmtime
)("(%u) !\n", wPeriod
);
306 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
307 return TIMERR_NOCANDO
;
311 /**************************************************************************
312 * timeEndPeriod [WINMM.138]
314 MMRESULT WINAPI
timeEndPeriod(UINT wPeriod
)
316 TRACE_(mmtime
)("(%u) !\n", wPeriod
);
318 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
319 return TIMERR_NOCANDO
;
323 /**************************************************************************
324 * timeEndPeriod [MMSYSTEM.606]
326 MMRESULT16 WINAPI
timeEndPeriod16(UINT16 wPeriod
)
328 TRACE_(mmtime
)("(%u) !\n", wPeriod
);
329 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
330 return TIMERR_NOCANDO
;
334 /**************************************************************************
335 * timeGetTime [MMSYSTEM.607][WINMM.141]
337 DWORD WINAPI
timeGetTime()
339 DWORD dwNewTick
= GetTickCount();
342 #ifdef USE_FAKE_MM_TIMERS
343 if (bUseFakeTimers
) {
344 if (!wInCallBackLoop
++) {
348 if (dwNewTick
< dwLastCBTick
) {
349 ERR_(mmtime
)("dwNewTick(%lu) < dwLastCBTick(%lu)\n", dwNewTick
, dwLastCBTick
);
351 dwDelta
= dwNewTick
- dwLastCBTick
;
352 if (dwDelta
> MMSYSTIME_MININTERVAL
) {
353 LPTIMERENTRY lpTimer
;
355 mmSysTimeMS
.u
.ms
+= dwDelta
; /* FIXME: faked timer */
356 dwLastCBTick
= dwNewTick
;
357 for (lpTimer
= lpTimerList
; lpTimer
!= NULL
; lpTimer
= lpTimer
->Next
) {
358 if (lpTimer
->wCurTime
< dwDelta
) {
359 TIME_TriggerCallBack(lpTimer
, dwNewTick
);
361 lpTimer
->wCurTime
-= dwDelta
;
366 dwNewTick
= mmSysTimeMS
.u
.ms
;