1 /**
2  * ae.ui.timer.sdl2.timer
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.ui.timer.sdl2.timer;
15 
16 import derelict.sdl2.sdl;
17 
18 public import ae.ui.timer.timer;
19 import ae.ui.app.application;
20 import ae.ui.shell.sdl2.shell : sdlEnforce;
21 
22 /// SDL implementation of `Timer`.
23 final class SDLTimer : Timer
24 {
25 	override TimerEvent setTimeout (AppCallback fn, uint ms) { return add(fn, ms, false); } ///
26 	override TimerEvent setInterval(AppCallback fn, uint ms) { return add(fn, ms, true ); } ///
27 
28 private:
29 	TimerEvent add(AppCallback fn, uint ms, bool recurring)
30 	{
31 		auto event = new SDLTimerEvent;
32 		event.fn = fn;
33 		event.recurring = recurring;
34 		event.id = sdlEnforce(SDL_AddTimer(ms, &sdlCallback, cast(void*)event));
35 		return event;
36 	}
37 
38 	extern(C) static uint sdlCallback(uint ms, void* param) nothrow
39 	{
40 		auto event = cast(SDLTimerEvent)param;
41 		try
42 			if (event.call())
43 				return ms;
44 			else
45 				return 0;
46 		catch (Exception e)
47 			throw new Error("Exception thrown from timer event", e);
48 	}
49 }
50 
51 private final class SDLTimerEvent : TimerEvent
52 {
53 	SDL_TimerID id;
54 	AppCallback fn;
55 	bool recurring, calling, cancelled;
56 
57 	// Returns true if it should be rescheduled.
58 	bool call()
59 	{
60 		calling = true;
61 		fn.call();
62 		calling = false;
63 		return recurring && !cancelled;
64 	}
65 
66 	override void cancel()
67 	{
68 		if (calling)
69 			cancelled = true;
70 		else
71 			SDL_RemoveTimer(id);
72 	}
73 }