A game framework written with osu! in mind.
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
2// See the LICENCE file in the repository root for full licence text.
3
4using System;
5using System.Runtime.InteropServices;
6
7namespace osu.Framework.Platform.Windows
8{
9 /// <summary>
10 /// Set the windows multimedia timer to a specific accuracy.
11 /// </summary>
12 internal class TimePeriod : IDisposable
13 {
14 private static readonly TimeCaps time_capabilities;
15
16 private readonly int period;
17
18 [DllImport(@"winmm.dll", ExactSpelling = true)]
19 private static extern int timeGetDevCaps(ref TimeCaps ptc, int cbtc);
20
21 [DllImport(@"winmm.dll", ExactSpelling = true)]
22 private static extern int timeBeginPeriod(int uPeriod);
23
24 [DllImport(@"winmm.dll", ExactSpelling = true)]
25 private static extern int timeEndPeriod(int uPeriod);
26
27 internal static int MinimumPeriod => time_capabilities.wPeriodMin;
28 internal static int MaximumPeriod => time_capabilities.wPeriodMax;
29
30 private readonly bool didAdjust;
31
32 static TimePeriod()
33 {
34 timeGetDevCaps(ref time_capabilities, Marshal.SizeOf(typeof(TimeCaps)));
35 }
36
37 internal TimePeriod(int period)
38 {
39 this.period = period;
40
41 if (MaximumPeriod <= 0)
42 return;
43
44 try
45 {
46 didAdjust = timeBeginPeriod(Math.Clamp(period, MinimumPeriod, MaximumPeriod)) == 0;
47 }
48 catch { }
49 }
50
51 #region IDisposable Support
52
53 private bool disposedValue; // To detect redundant calls
54
55 protected virtual void Dispose(bool disposing)
56 {
57 if (!disposedValue)
58 {
59 disposedValue = true;
60
61 if (!didAdjust)
62 return;
63
64 try
65 {
66 timeEndPeriod(period);
67 }
68 catch { }
69 }
70 }
71
72 ~TimePeriod()
73 {
74 Dispose(false);
75 }
76
77 public void Dispose()
78 {
79 Dispose(true);
80 GC.SuppressFinalize(this);
81 }
82
83 #endregion
84
85 [StructLayout(LayoutKind.Sequential)]
86 private readonly struct TimeCaps
87 {
88 internal readonly int wPeriodMin;
89 internal readonly int wPeriodMax;
90 }
91 }
92}