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());