1 /* -*- tab-width: 8; c-basic-offset: 4 -*- */
4 * MMSYTEM time functions
6 * Copyright 1993 Martin Ayotte
13 #include "wine/winbase16.h" /* GetTaskDS */
20 #define USE_FAKE_MM_TIMERS
22 static MMTIME16 mmSysTimeMS
;
23 static MMTIME16 mmSysTimeSMPTE
;
25 typedef struct tagTIMERENTRY
{
35 struct tagTIMERENTRY
* Next
;
36 } TIMERENTRY
, *LPTIMERENTRY
;
38 static LPTIMERENTRY lpTimerList
= NULL
;
40 #ifdef USE_FAKE_MM_TIMERS
41 static DWORD dwLastCBTick
= 0;
42 static BOOL bUseFakeTimers
= FALSE
;
43 static WORD wInCallBackLoop
= 0;
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)
55 static void TIME_TriggerCallBack(LPTIMERENTRY lpTimer
, DWORD dwCurrent
)
57 lpTimer
->wCurTime
= lpTimer
->wDelay
;
59 if (lpTimer
->lpFunc
!= (FARPROC16
) NULL
) {
60 TRACE(mmtime
, "before CallBack16 (%lu)!\n", dwCurrent
);
61 TRACE(mmtime
, "lpFunc=%p wTimerID=%04X dwUser=%08lX !\n",
62 lpTimer
->lpFunc
, lpTimer
->wTimerID
, lpTimer
->dwUser
);
63 TRACE(mmtime
, "hInstance=%04X !\n", lpTimer
->hInstance
);
66 /* - TimeProc callback that is called here is something strange, under Windows 3.1x it is called
67 * during interrupt time, is allowed to execute very limited number of API calls (like
68 * PostMessage), and must reside in DLL (therefore uses stack of active application). So I
69 * guess current implementation via SetTimer has to be improved upon.
71 switch (lpTimer
->wFlags
& 0x30) {
72 case TIME_CALLBACK_FUNCTION
:
74 lpTimer
->lpFunc(lpTimer
->wTimerID
,0,lpTimer
->dwUser
,0,0);
76 Callbacks
->CallTimeFuncProc(lpTimer
->lpFunc
,
80 case TIME_CALLBACK_EVENT_SET
:
81 SetEvent((HANDLE
)lpTimer
->lpFunc
);
83 case TIME_CALLBACK_EVENT_PULSE
:
84 PulseEvent((HANDLE
)lpTimer
->lpFunc
);
87 FIXME(mmtime
,"Unknown callback type 0x%04x for mmtime callback (%p),ignored.\n",lpTimer
->wFlags
,lpTimer
->lpFunc
);
90 TRACE(mmtime
, "after CallBack16 !\n");
92 if (lpTimer
->wFlags
& TIME_ONESHOT
)
93 timeKillEvent(lpTimer
->wTimerID
);
96 /**************************************************************************
97 * TIME_MMSysTimeCallback
99 static VOID WINAPI
TIME_MMSysTimeCallback( HWND hwnd
, UINT msg
,
100 UINT id
, DWORD dwTime
)
102 LPTIMERENTRY lpTimer
;
104 mmSysTimeMS
.u
.ms
+= MMSYSTIME_MININTERVAL
;
105 mmSysTimeSMPTE
.u
.smpte
.frame
++;
107 #ifdef USE_FAKE_MM_TIMERS
109 dwLastCBTick
= GetTickCount();
111 if (!wInCallBackLoop
++)
113 for (lpTimer
= lpTimerList
; lpTimer
!= NULL
; lpTimer
= lpTimer
->Next
) {
114 if (lpTimer
->wCurTime
< MMSYSTIME_MININTERVAL
) {
115 TIME_TriggerCallBack(lpTimer
, dwTime
);
117 lpTimer
->wCurTime
-= MMSYSTIME_MININTERVAL
;
120 #ifdef USE_FAKE_MM_TIMERS
125 /**************************************************************************
126 * StartMMTime [internal]
128 static void StartMMTime()
130 static BOOL mmTimeStarted
= FALSE
;
132 if (!mmTimeStarted
) {
133 mmTimeStarted
= TRUE
;
134 mmSysTimeMS
.wType
= TIME_MS
;
135 mmSysTimeMS
.u
.ms
= 0;
136 mmSysTimeSMPTE
.wType
= TIME_SMPTE
;
137 mmSysTimeSMPTE
.u
.smpte
.hour
= 0;
138 mmSysTimeSMPTE
.u
.smpte
.min
= 0;
139 mmSysTimeSMPTE
.u
.smpte
.sec
= 0;
140 mmSysTimeSMPTE
.u
.smpte
.frame
= 0;
141 mmSysTimeSMPTE
.u
.smpte
.fps
= 0;
142 mmSysTimeSMPTE
.u
.smpte
.dummy
= 0;
143 SetTimer( 0, 0, MMSYSTIME_MININTERVAL
, TIME_MMSysTimeCallback
);
144 #ifdef USE_FAKE_MM_TIMERS
145 bUseFakeTimers
= PROFILE_GetWineIniBool("options", "MMFakeTimers", TRUE
);
146 TRACE(mmtime
, "FakeTimer=%c\n", bUseFakeTimers
? 'Y' : 'N');
148 dwLastCBTick
= GetTickCount();
153 /**************************************************************************
154 * timeGetSystemTime [WINMM.140]
156 MMRESULT WINAPI
timeGetSystemTime(LPMMTIME lpTime
, UINT wSize
)
158 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
160 lpTime
->wType
= TIME_MS
;
161 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
165 /**************************************************************************
166 * timeGetSystemTime [MMSYSTEM.601]
168 MMRESULT16 WINAPI
timeGetSystemTime16(LPMMTIME16 lpTime
, UINT16 wSize
)
170 TRACE(mmsys
, "(%p, %u);\n", lpTime
, wSize
);
172 lpTime
->wType
= TIME_MS
;
173 lpTime
->u
.ms
= mmSysTimeMS
.u
.ms
;
177 static WORD
timeSetEventInternal(UINT wDelay
,UINT wResol
,
178 FARPROC16 lpFunc
,DWORD dwUser
,
179 UINT wFlags
, UINT16 isWin32
)
182 LPTIMERENTRY lpNewTimer
;
183 LPTIMERENTRY lpTimer
= lpTimerList
;
185 TRACE(mmtime
, "(%u, %u, %p, %08lX, %04X);\n",
186 wDelay
, wResol
, lpFunc
, dwUser
, wFlags
);
188 lpNewTimer
= (LPTIMERENTRY
)xmalloc(sizeof(TIMERENTRY
));
189 if (lpNewTimer
== NULL
)
191 while (lpTimer
!= NULL
) {
192 wNewID
= MAX(wNewID
, lpTimer
->wTimerID
);
193 lpTimer
= lpTimer
->Next
;
196 lpNewTimer
->Next
= lpTimerList
;
197 lpTimerList
= lpNewTimer
;
198 lpNewTimer
->wTimerID
= wNewID
+ 1;
199 lpNewTimer
->wCurTime
= wDelay
;
200 lpNewTimer
->wDelay
= wDelay
;
201 lpNewTimer
->wResol
= wResol
;
202 lpNewTimer
->lpFunc
= lpFunc
;
203 lpNewTimer
->isWin32
= isWin32
;
204 lpNewTimer
->hInstance
= GetTaskDS16();
205 TRACE(mmtime
, "hInstance=%04X !\n", lpNewTimer
->hInstance
);
206 TRACE(mmtime
, "lpFunc=0x%08lx !\n", (DWORD
)lpFunc
);
207 lpNewTimer
->dwUser
= dwUser
;
208 lpNewTimer
->wFlags
= wFlags
;
209 return lpNewTimer
->wTimerID
;
212 /**************************************************************************
213 * timeSetEvent [MMSYSTEM.602]
215 MMRESULT WINAPI
timeSetEvent(UINT wDelay
,UINT wResol
,
216 LPTIMECALLBACK lpFunc
,DWORD dwUser
,
219 return timeSetEventInternal(wDelay
, wResol
, (FARPROC16
)lpFunc
,
223 /**************************************************************************
224 * timeSetEvent [MMSYSTEM.602]
226 MMRESULT16 WINAPI
timeSetEvent16(UINT16 wDelay
, UINT16 wResol
,
227 LPTIMECALLBACK16 lpFunc
,DWORD dwUser
,
230 return timeSetEventInternal(wDelay
, wResol
, (FARPROC16
)lpFunc
,
234 /**************************************************************************
235 * timeKillEvent [WINMM.142]
237 MMRESULT WINAPI
timeKillEvent(UINT wID
)
239 LPTIMERENTRY
* lpTimer
;
241 for (lpTimer
= &lpTimerList
; *lpTimer
; lpTimer
= &((*lpTimer
)->Next
)) {
242 if (wID
== (*lpTimer
)->wTimerID
) {
243 LPTIMERENTRY xlptimer
= (*lpTimer
)->Next
;
253 /**************************************************************************
254 * timeKillEvent [MMSYSTEM.603]
256 MMRESULT16 WINAPI
timeKillEvent16(UINT16 wID
)
258 return timeKillEvent(wID
);
261 /**************************************************************************
262 * timeGetDevCaps [WINMM.139]
264 MMRESULT WINAPI
timeGetDevCaps(LPTIMECAPS lpCaps
,UINT wSize
)
266 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
268 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
269 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
273 /**************************************************************************
274 * timeGetDevCaps [MMSYSTEM.604]
276 MMRESULT16 WINAPI
timeGetDevCaps16(LPTIMECAPS16 lpCaps
, UINT16 wSize
)
278 TRACE(mmtime
, "(%p, %u) !\n", lpCaps
, wSize
);
280 lpCaps
->wPeriodMin
= MMSYSTIME_MININTERVAL
;
281 lpCaps
->wPeriodMax
= MMSYSTIME_MAXINTERVAL
;
285 /**************************************************************************
286 * timeBeginPeriod [WINMM.137]
288 MMRESULT WINAPI
timeBeginPeriod(UINT wPeriod
)
290 TRACE(mmtime
, "(%u) !\n", wPeriod
);
292 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
293 return TIMERR_NOCANDO
;
296 /**************************************************************************
297 * timeBeginPeriod [MMSYSTEM.605]
299 MMRESULT16 WINAPI
timeBeginPeriod16(UINT16 wPeriod
)
301 TRACE(mmtime
, "(%u) !\n", wPeriod
);
303 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
304 return TIMERR_NOCANDO
;
308 /**************************************************************************
309 * timeEndPeriod [WINMM.138]
311 MMRESULT WINAPI
timeEndPeriod(UINT wPeriod
)
313 TRACE(mmtime
, "(%u) !\n", wPeriod
);
315 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
316 return TIMERR_NOCANDO
;
320 /**************************************************************************
321 * timeEndPeriod [MMSYSTEM.606]
323 MMRESULT16 WINAPI
timeEndPeriod16(UINT16 wPeriod
)
325 TRACE(mmtime
, "(%u) !\n", wPeriod
);
326 if (wPeriod
< MMSYSTIME_MININTERVAL
|| wPeriod
> MMSYSTIME_MAXINTERVAL
)
327 return TIMERR_NOCANDO
;
331 /**************************************************************************
332 * timeGetTime [MMSYSTEM.607][WINMM.141]
334 DWORD WINAPI
timeGetTime()
336 DWORD dwNewTick
= GetTickCount();
339 #ifdef USE_FAKE_MM_TIMERS
340 if (bUseFakeTimers
) {
341 if (wInCallBackLoop
++) {
345 if (dwNewTick
< dwLastCBTick
) {
346 ERR(mmtime
, "dwNewTick(%lu) < dwLastCBTick(%lu)\n", dwNewTick
, dwLastCBTick
);
348 dwDelta
= dwNewTick
- dwLastCBTick
;
349 if (dwDelta
> MMSYSTIME_MININTERVAL
) {
350 LPTIMERENTRY lpTimer
;
352 mmSysTimeMS
.u
.ms
+= dwDelta
; /* FIXME: faked timer */
353 dwLastCBTick
= dwNewTick
;
354 for (lpTimer
= lpTimerList
; lpTimer
!= NULL
; lpTimer
= lpTimer
->Next
) {
355 if (lpTimer
->wCurTime
< dwDelta
) {
356 TIME_TriggerCallBack(lpTimer
, dwNewTick
);
358 lpTimer
->wCurTime
-= dwDelta
;
361 dwNewTick
= mmSysTimeMS
.u
.ms
;