1 module gfm.sdl2.timer;
2 
3 import core.stdc.stdlib;
4 
5 import bindbc.sdl;
6 
7 import gfm.sdl2.sdl;
8 
9 /// SDL Timer wrapper.
10 class SDL2Timer
11 {
12     public
13     {
14         /// Create a new SDL timer.
15         /// See_also: $(LINK https://wiki.libsdl.org/SDL_AddTimer)
16         /// Throws: $(D SDL2Exception) on error.
17         this(SDL2 sdl2, uint intervalMs)
18         {
19             _id = SDL_AddTimer(intervalMs, &timerCallbackSDL, cast(void*)this);
20             if (_id == 0)
21                 sdl2.throwSDL2Exception("SDL_AddTimer");
22         }
23 
24         /// Returns: Timer ID.
25         SDL_TimerID id() pure const nothrow @nogc
26         {
27             return _id;
28         }
29 
30         /// Timer clean-up.
31         /// See_also: $(LINK https://wiki.libsdl.org/SDL_RemoveTimer)
32         ~this()
33         {
34             if (_id != 0)
35             {
36                 debug ensureNotInGC("SDL2Timer");
37                 SDL_RemoveTimer(_id);
38                 _id = 0;
39             }
40         }
41     }
42 
43     protected
44     {
45         /// Override this to implement a SDL timer.
46         abstract uint onTimer(uint interval) nothrow;
47     }
48 
49     private
50     {
51         SDL_TimerID _id;
52     }
53 }
54 
55 extern(C) private nothrow
56 {
57     uint timerCallbackSDL(uint interval, void* param)
58     {
59         try
60         {
61             SDL2Timer timer = cast(SDL2Timer)param;
62             return timer.onTimer(interval);
63         }
64         catch (Throwable e)
65         {
66             // No Throwable is supposed to cross C callbacks boundaries
67             // Crash immediately
68             exit(-1);
69             static if (!codeAfterExitIsDead)
70                 return 0;
71         }
72     }
73 }
74 
75 private struct TestIfCodeAfterExitIsDead
76 {
77     static int test()()
78     {
79         try
80         {
81             return 0;
82         }
83         catch (Throwable e)
84         {
85             exit(-1);
86         }
87     }
88 }
89 
90 /// Does this compiler deduces that code after `exit()` is dead?
91 enum codeAfterExitIsDead = __traits(compiles, TestIfCodeAfterExitIsDead.test());