1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 module dfl.timer; 5 6 import core.sys.windows.windows; 7 import dfl.exception; 8 import dfl.event; 9 import dfl.base; 10 import dfl.application; 11 import dfl.internal.dlib; 12 13 debug (APP_PRINT) { 14 private import dfl.internal.clib; 15 } 16 17 class Timer { 18 //EventHandler tick; 19 Event!(Timer, EventArgs) tick; 20 21 @property void enabled(bool on) { 22 if (on) { 23 start(); 24 } else { 25 stop(); 26 } 27 } 28 29 @property bool enabled() { 30 return timerId != 0; 31 } 32 33 final @property void interval(size_t timeout) { 34 if (!timeout) { 35 throw new DflException("Invalid timer interval"); 36 } 37 38 if (this._timeout != timeout) { 39 this._timeout = timeout; 40 41 if (timerId) { 42 // I don't know if this is the correct behavior. 43 // Reset the timer for the new timeout... 44 stop(); 45 start(); 46 } 47 } 48 } 49 50 final @property size_t interval() { 51 return _timeout; 52 } 53 54 final void start() { 55 if (timerId) { 56 return; 57 } 58 59 assert(_timeout > 0); 60 61 timerId = SetTimer(null, 0, _timeout, &timerProc); 62 if (!timerId) { 63 throw new DflException("Unable to start timer"); 64 } 65 allTimers[timerId] = this; 66 } 67 68 final void stop() { 69 if (timerId) { 70 //delete allTimers[timerId]; 71 allTimers.remove(timerId); 72 KillTimer(null, timerId); 73 timerId = 0; 74 } 75 } 76 77 this() { 78 } 79 80 this(void delegate(Timer) dg) { 81 this(); 82 if (dg) { 83 this._dg = dg; 84 tick ~= &_dgcall; 85 } 86 } 87 88 this(void delegate(Object, EventArgs) dg) { 89 assert(dg !is null); 90 91 this(); 92 tick ~= dg; 93 } 94 95 this(void delegate(Timer, EventArgs) dg) { 96 assert(dg !is null); 97 98 this(); 99 tick ~= dg; 100 } 101 102 ~this() { 103 dispose(); 104 } 105 106 protected: 107 108 void dispose() { 109 stop(); 110 } 111 112 void onTick(EventArgs ea) { 113 tick(this, ea); 114 } 115 116 private: 117 DWORD _timeout = 100; 118 UINT timerId = 0; 119 void delegate(Timer) _dg; 120 121 void _dgcall(Object sender, EventArgs ea) { 122 assert(_dg !is null); 123 _dg(this); 124 } 125 } 126 127 private: 128 129 Timer[UINT] allTimers; 130 131 extern (Windows) void timerProc(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) nothrow { 132 try { 133 if (idEvent in allTimers) { 134 allTimers[idEvent].onTick(EventArgs.empty); 135 } else { 136 debug (APP_PRINT) 137 cprintf("Unknown timer 0x%X.\n", idEvent); 138 } 139 } 140 catch (DThrowable e) { 141 Application.onThreadException(e); 142 } 143 }