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