The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
timer.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Mark de Wever <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "gui/core/timer.hpp"
16 
17 #include "events.hpp"
18 #include "gui/core/log.hpp"
19 
20 #include <SDL_timer.h>
21 
22 #include <map>
23 
24 namespace gui2
25 {
26 
27 struct ttimer
28 {
30  {
31  }
32 
33  SDL_TimerID sdl_id;
34  Uint32 interval;
35  std::function<void(size_t id)> callback;
36 };
37 
38 /** Ids for the timers. */
39 static size_t id = 0;
40 
41 /** The active timers. */
42 static std::map<size_t, ttimer> timers;
43 
44 /** The id of the event being executed, 0 if none. */
45 static size_t executing_id = 0;
46 
47 /** Did somebody try to remove the timer during its execution? */
48 static bool executing_id_removed = false;
49 
50 /**
51  * Helper to make removing a timer in a callback safe.
52  *
53  * Upon creation it sets the executing id and clears the remove request flag.
54  *
55  * If an remove_timer() is called for the id being executed it requests a
56  * remove the timer and exits remove_timer().
57  *
58  * Upon destruction it tests whether there was a request to remove the id and
59  * does so. It also clears the executing id. It leaves the remove request flag
60  * since the execution function needs to know whether or not the event was
61  * removed.
62  */
63 class texecutor
64 {
65 public:
66  texecutor(size_t id)
67  {
68  executing_id = id;
69  executing_id_removed = false;
70  }
71 
73  {
74  const size_t id = executing_id;
75  executing_id = 0;
76  if(executing_id_removed) {
77  remove_timer(id);
78  }
79  }
80 };
81 
82 extern "C" {
83 
84 static Uint32 timer_callback(Uint32, void* id)
85 {
86  DBG_GUI_E << "Pushing timer event in queue.\n";
87 
89  = timers.find(reinterpret_cast<size_t>(id));
90  if(itor == timers.end()) {
91  return 0;
92  }
93 
94  SDL_Event event;
95  SDL_UserEvent data;
96 
97  data.type = TIMER_EVENT;
98  data.code = 0;
99  data.data1 = id;
100  data.data2 = nullptr;
101 
102  event.type = TIMER_EVENT;
103  event.user = data;
104 
105  SDL_PushEvent(&event);
106 
107  return itor->second.interval;
108 }
109 
110 } // extern "C"
111 
112 size_t add_timer(const Uint32 interval,
113  const std::function<void(size_t id)>& callback,
114  const bool repeat)
115 {
116  static_assert(sizeof(size_t) == sizeof(void*), "Pointer and size_t are not the same size");
117 
118  DBG_GUI_E << "Adding timer.\n";
119 
120  do {
121  ++id;
122  } while(id == 0 || timers.find(id) != timers.end());
123 
124  ttimer timer;
125  timer.sdl_id = SDL_AddTimer(
126  interval, timer_callback, reinterpret_cast<void*>(id));
127  if(timer.sdl_id == 0) {
128  WRN_GUI_E << "Failed to create an sdl timer." << std::endl;
129  return 0;
130  }
131 
132  if(repeat) {
133  timer.interval = interval;
134  }
135 
136  timer.callback = callback;
137 
138  timers.insert(std::make_pair(id, timer));
139 
140  DBG_GUI_E << "Added timer " << id << ".\n";
141  return id;
142 }
143 
144 bool remove_timer(const size_t id)
145 {
146  DBG_GUI_E << "Removing timer " << id << ".\n";
147 
148  std::map<size_t, ttimer>::iterator itor = timers.find(id);
149  if(itor == timers.end()) {
150  LOG_GUI_E << "Can't remove timer since it no longer exists.\n";
151  return false;
152  }
153 
154  if(id == executing_id) {
155  executing_id_removed = true;
156  return true;
157  }
158 
159  if(!SDL_RemoveTimer(itor->second.sdl_id)) {
160  /*
161  * This can happen if the caller of the timer didn't get the event yet
162  * but the timer has already been fired. This due to the fact that a
163  * timer pushes an event in the queue, which allows the following
164  * condition:
165  * - Timer fires
166  * - Push event in queue
167  * - Another event is processed and tries to remove the event.
168  */
169  DBG_GUI_E << "The timer is already out of the SDL timer list.\n";
170  }
171  timers.erase(itor);
172  return true;
173 }
174 
175 bool execute_timer(const size_t id)
176 {
177  DBG_GUI_E << "Executing timer " << id << ".\n";
178 
179  std::map<size_t, ttimer>::iterator itor = timers.find(id);
180  if(itor == timers.end()) {
181  LOG_GUI_E << "Can't execute timer since it no longer exists.\n";
182  return false;
183  }
184 
185  {
186  texecutor executor(id);
187  itor->second.callback(id);
188  }
189 
190  if(!executing_id_removed && itor->second.interval == 0) {
191  timers.erase(itor);
192  }
193  return true;
194 }
195 
196 } // namespace gui2
Define the common log macros for the gui toolkit.
static bool executing_id_removed
Did somebody try to remove the timer during its execution?
Definition: timer.cpp:48
#define LOG_GUI_E
Definition: log.hpp:36
#define TIMER_EVENT
Definition: events.hpp:24
bool remove_timer(const size_t id)
Removes a timer.
Definition: timer.cpp:144
static std::map< size_t, ttimer > timers
The active timers.
Definition: timer.cpp:42
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
SDL_TimerID sdl_id
Definition: timer.cpp:33
A class inherited from ttext_box that displays its input as stars.
Definition: field-fwd.hpp:23
Helper to make removing a timer in a callback safe.
Definition: timer.cpp:63
static size_t id
Ids for the timers.
Definition: timer.cpp:39
texecutor(size_t id)
Definition: timer.cpp:66
std::map< std::string, tfilter >::iterator itor
Definition: filter.cpp:199
#define DBG_GUI_E
Definition: log.hpp:35
#define WRN_GUI_E
Definition: log.hpp:37
Contains the gui2 timer routines.
static size_t executing_id
The id of the event being executed, 0 if none.
Definition: timer.cpp:45
bool execute_timer(const size_t id)
Executes a timer.
Definition: timer.cpp:175
cl_event event
Definition: glew.h:3070
Uint32 interval
Definition: timer.cpp:34
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
std::function< void(size_t id)> callback
Definition: timer.cpp:35
size_t add_timer(const Uint32 interval, const std::function< void(size_t id)> &callback, const bool repeat)
Adds a new timer.
Definition: timer.cpp:112
static Uint32 timer_callback(Uint32, void *id)
Definition: timer.cpp:84