]> git.vomp.tv Git - vompclient.git/blob - sleeptimer.cc
OSDOpenVG: Render on demand: Fix backing out of a view render race
[vompclient.git] / sleeptimer.cc
1 /*
2     Copyright 2008 Thomas Steger
3     Copyright 2020 Chris Tallon
4
5     This file is part of VOMP.
6
7     VOMP is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     VOMP is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "defines.h"
22 #include "log.h"
23 #include "input.h"
24 #include "wsymbol.h"
25 #include "colour.h"
26 #include "video.h"
27 #include "boxstack.h"
28 #include "message.h"
29 #include "messagequeue.h"
30 #include "util.h"
31 #include "i18n.h"
32
33 #include "sleeptimer.h"
34
35 SleepTimer::SleepTimer()
36 {
37   logger = Log::getInstance();
38   boxstack = BoxStack::getInstance();
39   timers = Timers::getInstance();
40 }
41
42 // --- Input Functions ----
43
44 void SleepTimer::go()  // User presses GO, from Control
45 {
46   std::lock_guard<std::mutex> lg(stateLock);
47
48   if (state == 0) // inactive
49   {
50     calcNewTime();
51
52     vsleeptimer = new VSleepTimer();
53     vsleeptimer->setTime(timerText);
54     vsleeptimer->draw();
55     boxstack->add(vsleeptimer);
56     boxstack->update(vsleeptimer);
57
58     timers->setTimerD(this, 1, 3); // 3s remove vsleeptimer timer
59     timers->setTimerD(this, 2, sec - 31); // logic timer 31s before end
60
61     state = 2;
62   }
63   else if (state == 1) // counting, no displays - display current running time
64   {
65     calcCurrentSec();
66
67     vsleeptimer = new VSleepTimer();
68     vsleeptimer->setTime(liveText);
69     vsleeptimer->draw();
70     boxstack->add(vsleeptimer);
71     boxstack->update(vsleeptimer);
72
73     timers->setTimerD(this, 1, 3); // 3s remove vsleeptimer timer
74     state = 2;
75   }
76   else if (state == 2) // counting, modify display showing already.
77   {
78     calcNewTime();
79
80     vsleeptimer->setTime(timerText);
81     vsleeptimer->draw();
82     boxstack->update(vsleeptimer);
83
84     timers->setTimerD(this, 1, 3); // update existing remove vsleeptimer timer
85     if (sec == -1)
86     {
87       timers->cancelTimer(this, 2);
88       state = 4; // user went beyond 2h, turning it off
89     }
90     else
91     {
92       timers->setTimerD(this, 2, sec - 31); // reset the logic timer 31s before end
93     }
94   }
95   else if (state == 3) // counting, countdown display showing. turn it off
96   {
97     timers->cancelTimer(this, 2);
98
99     vsleeptimer = new VSleepTimer(); // Show a new VSleepTimer OFF dialogue
100     vsleeptimer->setTime(tr("OFF"));
101     vsleeptimer->draw();
102     boxstack->add(vsleeptimer);
103     boxstack->update(vsleeptimer);
104
105     boxstack->remove(vcountdown); // this deletes vcountdown as well
106     vcountdown = NULL;
107
108     timers->setTimerD(this, 1, 3); // 3s remove vsleeptimer timer
109     state = 4;
110   }
111   else if (state == 4) // not counting, OFF dialogue showing
112   {
113     boxstack->remove(vsleeptimer);
114     vsleeptimer = NULL;
115     state = 0;
116   }
117 }
118
119 void SleepTimer::timercall(int clientReference)
120 {
121   std::lock_guard<std::mutex> lg(stateLock);
122
123   if (clientReference == 1) // Remove the VSleepTimer
124   {
125     if (state == 2 || state == 4)  // modify display showing, counting or not
126     {
127       boxstack->remove(vsleeptimer);
128       vsleeptimer = NULL;
129       if      (state == 2) state = 1;
130       else if (state == 4) state = 0;
131     }
132   }
133   else if (clientReference == 2) // sleep timer logic
134   {
135     if (state == 0) // inactive
136     {
137       logger->log("SleepTimer", Log::ERR, "Received timercall when state 0");
138     }
139     else if (state == 1 || state == 2) // counting (either with or without modify display showing)
140     {
141       if (state == 2) // counting, modify display showing
142       {
143         // User has very recently pressed the sleeptimer button and the modify display / livetext is showing
144         // But now the logic timer has fired for the first time in the countdown.
145         // Delete the vsleeptimer before going on
146
147         boxstack->remove(vsleeptimer);
148         vsleeptimer = NULL;
149         state = 1;
150       }
151
152       // To receive a timer now means we are starting the countdown
153       calcCurrentSec();
154
155       vcountdown = new VCountdown(); // Show a new VCountdown dialogue
156       vcountdown->setTime(sec);
157       vcountdown->draw();
158       boxstack->add(vcountdown);
159       boxstack->update(vcountdown);
160
161       timers->setTimerD(this, 2, 1); // logic timer every 1s
162       state = 3;
163     }
164     else if (state == 3) // counting, countdown display showing
165     {
166       calcCurrentSec();
167
168       if (sec > -1) // update countdown
169       {
170         vcountdown->setTime(sec);
171         vcountdown->draw();
172         boxstack->update(vcountdown);
173         timers->setTimerD(this, 2, 1); // logic timer every 1s
174       }
175       else // end of countdown
176       {
177         boxstack->remove(vcountdown);
178         vcountdown = NULL;
179         state = 0;
180
181         Message* m = new Message();
182         m->message = Message::INPUT_EVENT;
183         m->p_to = Message::CONTROL;
184         m->from = this;
185         m->parameter = Input::POWER;
186         MessageQueue::getInstance()->postMessage(m);
187       }
188     }
189     else if (state == 4) // not counting, off dialogue showing
190     {
191       logger->log("SleepTimer", Log::ERR, "Received timercall when state 4");
192     }
193   }
194 }
195
196 void SleepTimer::shutdown()
197 {
198   std::lock_guard<std::mutex> lg(stateLock);
199
200   // Cancel any logic timer
201   if (state == 1 || state == 2 || state == 3)
202     timers->cancelTimer(this, 2);
203
204   // Cancel any remove-vsleeptimer counter
205   if (state > 1) timers->cancelTimer(this, 1);
206
207   if (vsleeptimer)
208   {
209     boxstack->remove(vsleeptimer);
210     vsleeptimer = NULL;
211   }
212
213   if (vcountdown)
214   {
215     boxstack->remove(vcountdown);
216     vcountdown = NULL;
217   }
218
219   state = 0;
220   sec = -1;
221 }
222
223 // ------------------------
224
225 void SleepTimer::calcNewTime()
226 {
227   if      (sec <  890) { timerText = "0:15"; sec =  900; }
228   else if (sec < 1790) { timerText = "0:30"; sec = 1800; }
229   else if (sec < 2690) { timerText = "0:45"; sec = 2700; }
230   else if (sec < 3590) { timerText = "1:00"; sec = 3600; }
231   else if (sec < 4490) { timerText = "1:15"; sec = 4500; }
232   else if (sec < 5390) { timerText = "1:30"; sec = 5400; }
233   else if (sec < 6290) { timerText = "1:45"; sec = 6300; }
234   else if (sec < 7190) { timerText = "2:00"; sec = 7200; }
235   else                 { timerText = tr("OFF"); sec = -1; }
236
237   endTime = std::chrono::system_clock::now() + std::chrono::seconds(sec);
238 }
239
240 void SleepTimer::calcCurrentSec()
241 {
242   auto remainingTime = endTime - std::chrono::system_clock::now();
243   auto remainingTimeS = std::chrono::duration_cast<std::chrono::seconds>(remainingTime);
244   sec = static_cast<int>(remainingTimeS.count()); // I think this chrono stuff is a bit too ... wordy .........
245   SNPRINTF(liveText, 10, "0:%02d", sec / 60);
246 }
247
248 // ------------ VSleepTimer class
249
250 VSleepTimer::VSleepTimer()
251 {
252   setSize(100, 28);
253   createBuffer();
254   if (Video::getInstance()->getFormat() == Video::PAL)
255   {
256     setPosition(100, 499);
257   }
258   else
259   {
260     setPosition(90, 400);
261   }
262
263   setBackgroundColour(DrawStyle::VIEWBACKGROUND);
264
265   wsClock.nextSymbol = WSymbol::CLOCK;
266   wsClock.setPosition(3, 0);
267   add(&wsClock);
268 }
269
270 void VSleepTimer::setTime(const char* text)
271 {
272   displaySleeptimer = text;
273 }
274
275 void VSleepTimer::draw()
276 {
277   Boxx::draw();
278   drawText(displaySleeptimer, 50, 2, DrawStyle::LIGHTTEXT);
279 }
280
281 // ------------ VCountdown class
282
283 VCountdown::VCountdown()
284 {
285   setSize(100, 28);
286   createBuffer();
287   if (Video::getInstance()->getFormat() == Video::PAL)
288   {
289     setPosition(100, 499);
290   }
291   else
292   {
293     setPosition(90, 400);
294   }
295
296   setBackgroundColour(DrawStyle::VIEWBACKGROUND);
297
298   wsClock.nextSymbol = WSymbol::CLOCK;
299   wsClock.nextColour = DrawStyle::RED;
300   wsClock.setPosition(3, 0);
301   add(&wsClock);
302 }
303
304 void VCountdown::setTime(int tsec)
305 {
306   sec = tsec;
307 }
308
309 void VCountdown::draw()
310 {
311   Boxx::draw();
312
313   char temp[10];
314   SNPRINTF(temp, 10, "0:%02d", sec);
315   drawText(temp, 50, 2, DrawStyle::RED);
316 }