]> git.vomp.tv Git - vompclient-marten.git/blob - command.cc
Switch over to updateView rather than show, EPG tweaks
[vompclient-marten.git] / command.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "command.h"
22
23 Command* Command::instance = NULL;
24
25 Command::Command()
26 {
27   if (instance) return;
28   instance = this;
29   initted = 0;
30   isStandby = 0;
31   firstBoot = 1;
32 }
33
34 Command::~Command()
35 {
36   instance = NULL;
37 }
38
39 Command* Command::getInstance()
40 {
41   return instance;
42 }
43
44 int Command::init()
45 {
46   if (initted) return 0;
47   initted = 1;
48
49   logger = Log::getInstance();
50   viewman = ViewMan::getInstance();
51   remote = Remote::getInstance();
52
53   if (!logger || !viewman || !remote)
54   {
55     initted = 0;
56     return 0;
57   }
58
59   pthread_mutex_init(&masterLock, NULL);
60
61   return 1;
62 }
63
64 int Command::shutdown()
65 {
66   if (!initted) return 0;
67   initted = 0;
68   return 1;
69 }
70
71 void Command::stop()
72 {
73 //  VDR::getInstance()->cancelFindingServer();
74   irun = 0;
75 }
76
77 void Command::run()
78 {
79   if (!initted) return;
80   irun = 1;
81
82   mainPid = getpid();
83
84   Video* video = Video::getInstance();
85
86   UCHAR screenSize = video->getFormat();
87
88   // moved from startup because surface delete doesn't work
89
90   // just in case
91   video->signalOn();
92   Led::getInstance()->on();
93
94   // Blue background
95   View* v = new View();
96   v->create(video->getScreenWidth(), video->getScreenHeight());
97   v->setBackgroundColour(Colour::VIDEOBLUE);
98   v->draw();
99   viewman->add(v);
100   viewman->updateView(v);
101   viewman->removeView(v);
102
103   // Wallpaper
104   wallpaper = new VWallpaper();
105   if (screenSize == Video::PAL)
106   {
107     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
108     wallpaper->init("/wallpaperPAL.jpg");
109   }
110   else
111   {
112     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
113     wallpaper->init("/wallpaperNTSC.jpg");
114   }
115   wallpaper->draw();
116   viewman->add(wallpaper);
117   viewman->updateView(wallpaper);
118
119   // End of startup. Lock the mutex and put the first view up
120
121   pthread_mutex_lock(&masterLock);
122
123
124   VConnect* vconnect = new VConnect();
125   viewman->add(vconnect);
126   vconnect->run();
127
128
129   UCHAR button = 0;
130   while(irun)
131   {
132     // unlock and wait
133     pthread_mutex_unlock(&masterLock);
134
135     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
136     // something happened, lock and process
137
138     pthread_mutex_lock(&masterLock);
139
140     if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue;
141
142     if (button != Remote::NA_SIGNAL) handleCommand(button);
143     processMessageQueue();
144   }
145
146   pthread_mutex_unlock(&masterLock);
147 }
148
149 void Command::postMessage(Message* m)
150 {
151   // This is locked here in case the main loop is not waiting for an event, but is processing one
152   // it could be killed but then not react to it because the signal wouldn't cause
153   // remote->getButtonPress to break
154   // locking the mutex ensures that the master thread is waiting on getButtonPress
155
156   pthread_mutex_lock(&masterLock);
157   MessageQueue::postMessage(m);
158   kill(mainPid, SIGURG);
159   pthread_mutex_unlock(&masterLock);
160 }
161
162 bool Command::postMessageIfNotBusy(Message* m)
163 {
164   // This is for the timers module
165   // If the masterlock is locked then the timers module wants to
166   // cancel delivery
167
168   if (pthread_mutex_trylock(&masterLock) != EBUSY)
169   {
170     MessageQueue::postMessage(m);
171     kill(mainPid, SIGURG);
172     pthread_mutex_unlock(&masterLock);
173     return true;
174   }
175   else
176   {
177     return false;
178   }
179 }
180
181 void Command::processMessage(Message* m)
182 {
183   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
184
185   switch(m->message)
186   {
187     case Message::STANDBY:
188     {
189       doStandby();
190       break;
191     }
192     case Message::STOP_PLAYBACK:
193     {
194       handleCommand(Remote::STOP); // an odd way of doing it, but so simple
195       break;
196     }
197     case Message::STREAM_END:
198     {
199       // post a message to ViewMan and then run the viewman message queue
200       Message* m2 = new Message();
201       m2->message = Message::STREAM_END;
202       m2->to = VVideoLive::getInstance();
203       viewman->postMessage(m2);
204       handleCommand(Remote::NA_NONE);
205       break;
206     }
207     case Message::VDR_CONNECTED:
208     {
209       doJustConnected((VConnect*)m->from);
210       break;
211     }
212     case Message::TIMER:
213     {
214       // FIXME - go to one message queue only - then instead of having
215       // objects deriving from messagequeues, make them derive from
216       // messagereceiver - then one messagequeue can deliver any message to anywhere
217
218       // Try to segfault
219       logger->log("Command", Log::DEBUG, "1: %p", m);
220       logger->log("Command", Log::DEBUG, "2: %p", m->to);
221       logger->log("Command", Log::DEBUG, "3: %lu", m->parameter);
222
223       // deliver timer
224
225       ((TimerReceiver*)m->to)->timercall(m->parameter);
226       handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
227                                       // run viewman message queue here. FIXME improve this!
228       // FIXME unlock main mutex
229     }
230   }
231 }
232
233 void Command::handleCommand(int button)
234 {
235   if (isStandby && (button != Remote::POWER)) return;
236
237   if (viewman->handleCommand(button)) return;
238
239   // command was not handled
240
241   switch(button)
242   {
243     case Remote::DF_LEFT:
244     case Remote::DF_RIGHT:
245     case Remote::VOLUMEUP:
246     case Remote::VOLUMEDOWN:
247     {
248       VVolume* v = new VVolume();
249       viewman->add(v);
250       v->handleCommand(button); // this will draw+show
251       return;
252     }
253     case Remote::MUTE:
254     {
255       VMute* v = new VMute();
256       v->draw();
257       viewman->add(v);
258       viewman->updateView(v);
259       return;
260     }
261     case Remote::POWER:
262     {
263       doStandby();
264       return;
265     }
266 #ifdef DEV
267     case Remote::RECORD:
268     {
269       Osd::getInstance()->screenShot("/out.jpg");
270       return;
271     }
272 #endif
273   }
274 }
275
276 void Command::doStandby()
277 {
278   if (isStandby)
279   {
280     Video::getInstance()->signalOn();
281     Led::getInstance()->on();
282     isStandby = 0;
283
284
285     VConnect* vconnect = new VConnect();
286     viewman->add(vconnect);
287     vconnect->run();
288   }
289   else
290   {
291     Video::getInstance()->signalOff();
292     viewman->removeAll();
293     viewman->updateView(wallpaper);
294
295     VDR::getInstance()->configSave("General", "Last Power State", "Off");
296     VDR::getInstance()->disconnect();
297     Led::getInstance()->off();
298     isStandby = 1;
299   }
300 }
301
302 void Command::doReboot()
303 {
304   VDR::getInstance()->disconnect();
305   // just kill it...
306   logger->log("Command", Log::NOTICE, "Reboot");
307   reboot(LINUX_REBOOT_CMD_RESTART);
308 }
309
310 void Command::doJustConnected(VConnect* vconnect)
311 {
312   I18n::initialize();
313   Video* video = Video::getInstance();
314   viewman->removeView(vconnect);
315
316   VInfo* vi = new VInfo();
317   vi->create(400, 200);
318   if (video->getFormat() == Video::PAL)
319     vi->setScreenPos(170, 200);
320   else
321     vi->setScreenPos(160, 150);
322
323   vi->setOneLiner(tr("Connected, loading config"));
324   vi->draw();
325   viewman->add(vi);
326   viewman->updateView(vi);
327
328   VDR* vdr = VDR::getInstance();
329   char* config;
330
331   // Power off if first boot and config says so
332   if (firstBoot)
333   {
334     firstBoot = 0;
335
336     logger->log("Command", Log::DEBUG, "Load power after boot");
337
338     config = vdr->configLoad("General", "Power After Boot");
339
340     if (config)
341     {
342       if (!strcasecmp(config, "On"))
343       {
344         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
345       }
346       else if (!strcasecmp(config, "Off"))
347       {
348         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
349         doStandby();
350         delete[] config;
351         return; // quit here
352       }
353       else if (!strcasecmp(config, "Last state"))
354       {
355         char* lastPowerState = vdr->configLoad("General", "Last Power State");
356         if (lastPowerState)
357         {
358           if (!strcasecmp(lastPowerState, "On"))
359           {
360             logger->log("Command", Log::INFO, "Config says Last Power State = On");
361           }
362           else if (!strcasecmp(lastPowerState, "Off"))
363           {
364             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
365             doStandby();
366             delete[] config;
367             return; // quit here
368           }
369           else
370           {
371             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
372           }
373         }
374         else
375         {
376           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
377         }
378       }
379       else
380       {
381         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
382       }
383       delete[] config;
384     }
385     else
386     {
387       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
388     }
389   }
390
391
392   // Go S-Video if config says so
393
394   config = vdr->configLoad("TV", "Connection");
395
396   if (config)
397   {
398     if (!strcasecmp(config, "S-Video"))
399     {
400       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
401       video->setConnection(Video::SVIDEO);
402     }
403     else
404     {
405       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
406       video->setConnection(Video::COMPOSITERGB);
407     }
408     delete[] config;
409   }
410   else
411   {
412     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
413   }
414
415   // Set remote type
416
417   config = vdr->configLoad("General", "Remote type");
418
419   if (config)
420   {
421     if (!strcasecmp(config, "New"))
422     {
423       logger->log("Command", Log::INFO, "Switching to New remote type");
424       remote->setRemoteType(Remote::NEWREMOTE);
425     }
426     else
427     {
428       logger->log("Command", Log::INFO, "Switching to Old remote type");
429       remote->setRemoteType(Remote::OLDREMOTE);
430     }
431     delete[] config;
432   }
433   else
434   {
435     logger->log("Command", Log::INFO, "Config General/Remote type not found");
436     remote->setRemoteType(Remote::OLDREMOTE);
437   }
438
439   // Get TV aspect ratio
440
441   config = vdr->configLoad("TV", "Aspect");
442   if (config)
443   {
444     if (!strcasecmp(config, "16:9"))
445     {
446       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
447       video->setTVsize(Video::ASPECT16X9);
448     }
449     else
450     {
451       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
452       video->setTVsize(Video::ASPECT4X3);
453     }
454     delete[] config;
455   }
456   else
457   {
458     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
459     video->setTVsize(Video::ASPECT4X3);
460   }
461
462   config = vdr->configLoad("TV", "Widemode");
463   if (config)
464   {
465     if (!strcasecmp(config, "Letterbox"))
466     {
467       logger->log("Command", Log::INFO, "Setting letterbox mode");
468       video->setMode(Video::LETTERBOX);
469     }
470     else
471     {
472       logger->log("Command", Log::INFO, "Setting chop-sides mode");
473       video->setMode(Video::NORMAL);
474     }
475     delete[] config;
476   }
477   else
478   {
479     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
480     video->setMode(Video::NORMAL);
481   }
482
483   // config done
484
485   // Save power state = on
486
487   vdr->configSave("General", "Last Power State", "On");
488
489
490   viewman->removeView(vi);
491
492   VWelcome* vw = new VWelcome();
493   vw->draw();
494   viewman->add(vw);
495   viewman->updateView(vw);
496 }