]> git.vomp.tv Git - vompclient.git/blob - control.cc
Minor code cleaning re: Messages
[vompclient.git] / control.cc
1 /*
2     Copyright 2004-2020 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 // FIXME rename to Control and move stuff from main to here
21
22 #ifndef WIN32
23 #include <unistd.h> // for reboot
24 #include <linux/reboot.h>
25 #include <sys/reboot.h>
26 #endif
27
28 #include <time.h>
29
30 #ifdef WIN32
31 #include "inputwin.h"
32 #endif
33
34 #ifdef __ANDROID__
35 #include "inputandroid.h"
36 #endif
37
38 #include "led.h"
39 #include "video.h"
40 #include "audio.h"
41 #include "vdr.h"
42 #include "vvolume.h"
43 #include "vserverselect.h"
44 #include "vwelcome.h"
45 #include "vmute.h"
46 #include "colour.h"
47 #include "osd.h"
48 #include "i18n.h"
49 #include "timers.h"
50 #include "wol.h"
51 #include "vconnect.h"
52 #include "message.h"
53 #include "inputman.h"
54 #include "input.h"
55 #include "vinfo.h"
56 #include "boxx.h"
57 #include "boxstack.h"
58 #include "log.h"
59 #include "sleeptimer.h"
60 #include "wjpeg.h"
61 #include "osdvector.h"
62
63
64 #ifdef VOMP_PLATFORM_RASPBERRY
65   #include "ledraspberry.h"
66   #include "osdopenvg.h"
67   #include "videoomx.h"
68   #include "audioomx.h"
69 #endif
70
71 #ifdef WIN32
72   #include "windowsosd.h"
73   #ifdef WINDOWS_LEGACY
74     #include "osdwinpixel.h"
75   #else
76     #include "osdwinvector.h"
77   #endif
78
79   #include "ledwin.h"
80   #include "videowin.h"
81   #include "audiowin.h"
82 #endif
83
84 #include "control.h"
85
86 static const char* TAG = "Control";
87
88 Control* Control::instance = NULL;
89
90 Control::Control()
91 {
92   if (instance) return;
93   instance = this;
94 }
95
96 Control::~Control()
97 {
98   flushMessageQueue();
99   instance = NULL;
100 }
101
102 Control* Control::getInstance()
103 {
104   return instance;
105 }
106
107 bool Control::init(bool tcrashed)
108 {
109   if (initted) return false;
110   crashed = tcrashed;
111   logger = LogNT::getInstance();
112
113   SkinFactory::InitSkin(0);
114
115   try
116   {
117     led = new Led_TYPE();                     if (!led) throw 10;
118     if (!led->init(-1))                       throw 11;  // FIXME init(0) on Win32
119
120     timers = new Timers();                    if (!timers) throw 20;
121     if (!timers->init())                      throw 21;
122
123     video = new Video_TYPE();                 if (!video) throw 30;
124     if (!video->init(Video::PAL))             throw 31;
125
126     audio = new Audio_TYPE();                 if (!audio) throw 40;
127     if (!audio->init(Audio::MPEG2_PES))       throw 41;
128
129     osd = new Osd_TYPE();                     if (!osd) throw 50;
130     if (!osd->init())                         throw 51;
131
132     vdr = new VDR();                          if (!vdr) throw 60;
133     if (!vdr->init())                         throw 61;
134
135     boxstack = new BoxStack();                if (!boxstack) throw 70;
136     if (!boxstack->init())                    throw 71;
137
138     sleepTimer = new SleepTimer();            if (!sleepTimer) throw 80;
139
140     wol = new Wol();                          if (!wol) throw 90;
141
142     inputMan = new InputMan();                if (!inputMan) throw 100;
143     if (!inputMan->init())                    throw 101;
144
145   }
146   catch (int e)
147   {
148     if      (e == 10) logger->crit(TAG, "LED module failed to create");
149     else if (e == 11) logger->crit(TAG, "LED module failed to initialise");
150     else if (e == 20) logger->crit(TAG, "Timers module failed to create");
151     else if (e == 21) logger->crit(TAG, "Timers module failed to initialise");
152     else if (e == 30) logger->crit(TAG, "Video module failed to create");
153     else if (e == 31) logger->crit(TAG, "Video module failed to initialise");
154     else if (e == 40) logger->crit(TAG, "Audio module failed to create");
155     else if (e == 41) logger->crit(TAG, "Audio module failed to initialise");
156     else if (e == 50) logger->crit(TAG, "OSD module failed to create");
157     else if (e == 51) logger->crit(TAG, "OSD module failed to initialise");
158     else if (e == 60) logger->crit(TAG, "VDR module failed to create");
159     else if (e == 61) logger->crit(TAG, "VDR module failed to initialise");
160     else if (e == 70) logger->crit(TAG, "BoxStack module failed to create");
161     else if (e == 71) logger->crit(TAG, "BoxStack module failed to initialise");
162     else if (e == 80) logger->crit(TAG, "SleepTimer module failed to create");
163     else if (e == 90) logger->crit(TAG, "WOL module failed to create");
164     else if (e == 100) logger->crit(TAG, "InputMan module failed to create");
165     else if (e == 101) logger->crit(TAG, "InputMan module failed to initialise");
166
167     switch(e)
168     {
169       case 101:
170         delete inputMan;
171         inputMan = NULL;
172         FALLTHROUGH
173       case 100:
174         delete wol;
175         wol = NULL;
176         FALLTHROUGH
177       case 90:
178         delete sleepTimer;
179         sleepTimer = NULL;
180         FALLTHROUGH
181       case 80:
182         boxstack->shutdown();
183         FALLTHROUGH
184       case 71:
185         delete boxstack;
186         boxstack = NULL;
187         FALLTHROUGH
188       case 70:
189         vdr->shutdown();
190         FALLTHROUGH
191       case 61:
192         delete vdr;
193         vdr = NULL;
194         FALLTHROUGH
195       case 60:
196         osd->shutdown();
197         FALLTHROUGH
198       case 51:
199         delete osd;
200         osd = NULL;
201         FALLTHROUGH
202       case 50:
203         audio->shutdown();
204         FALLTHROUGH
205       case 41:
206         delete audio;
207         audio = NULL;
208         FALLTHROUGH
209       case 40:
210         video->shutdown();
211         FALLTHROUGH
212       case 31:
213         delete video;
214         video = NULL;
215         FALLTHROUGH
216       case 30:
217         timers->shutdown();
218         FALLTHROUGH
219       case 21:
220         delete timers;
221         timers = NULL;
222         FALLTHROUGH
223       case 20:
224         led->shutdown();
225         FALLTHROUGH
226       case 11:
227         delete led;
228         led = NULL;
229         FALLTHROUGH
230       case 10:
231         FALLTHROUGH
232         ;
233     }
234
235     return false;
236   }
237
238   initted = true;
239   return true;
240 }
241
242 void Control::shutdown()
243 {
244   if (!initted) return;
245   initted = false;
246
247   if (inputMan)
248   {
249     inputMan->shutdown();
250     delete inputMan;
251     inputMan = NULL;
252     logger->info(TAG, "InputMan module shut down");
253   }
254
255   if (wol)
256   {
257     delete wol;
258     logger->info(TAG, "WOL module shut down");
259   }
260
261   if (sleepTimer)
262   {
263     delete sleepTimer;
264     sleepTimer = NULL;
265     logger->info(TAG, "SleepTimer module shut down");
266   }
267
268   if (boxstack)
269   {
270     boxstack->shutdown();
271     delete boxstack;
272     boxstack = NULL;
273     logger->info(TAG, "BoxStack module shut down");
274   }
275
276   if (vdr)
277   {
278     vdr->shutdown();
279     delete vdr;
280     vdr = NULL;
281     logger->info(TAG, "VDR module shut down");
282   }
283
284   if (osd)
285   {
286     osd->shutdown();
287     delete osd;
288     osd = NULL;
289     logger->info(TAG, "OSD module shut down");
290   }
291
292   if (audio)
293   {
294     audio->shutdown();
295     delete audio;
296     audio = NULL;
297     logger->info(TAG, "Audio module shut down");
298   }
299
300   if (video)
301   {
302     video->shutdown();
303     delete video;
304     video = NULL;
305     logger->info(TAG, "Video module shut down");
306   }
307
308   if (timers)
309   {
310     timers->shutdown();
311     delete timers;
312     timers = NULL;
313     logger->info(TAG, "Timers module shut down");
314   }
315
316   if (led)
317   {
318     led->shutdown();
319     delete led;
320     led = NULL;
321     logger->info(TAG, "LED module shut down");
322   }
323 }
324
325 void Control::stop()
326 {
327   logger->info(TAG, "Request stop");
328
329   Message* m = new Message(); // break master loop
330   m->message = Message::SHUTDOWN;
331   m->p_to = Message::CONTROL;
332   postMessage(m);
333 }
334
335 void Control::doWallpaper()
336 {
337   // Blue background
338   Boxx* bbg = new Boxx();
339   bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
340   bbg->createBuffer();
341   bbg->fillColour(DrawStyle::WALLPAPER);
342   boxstack->add(bbg);
343   boxstack->update(bbg);
344   boxstack->remove(bbg);
345
346   // Wallpaper
347   wallpaper = new Boxx();
348   wallpaper->setSize(video->getScreenWidth(), video->getScreenHeight());
349   wallpaper->createBuffer();
350   wallpaper->setBackgroundColour(DrawStyle::WALLPAPER);
351
352   wallpaper_pict = new WJpegTYPE();
353   wallpaper_pict->setSize(video->getScreenWidth(), video->getScreenHeight());
354
355   if (video->getFormat() == Video::PAL)
356   {
357     logger->debug(TAG, "PAL wallpaper selected");
358 #ifndef _MIPS_ARCH    
359     wallpaper_pict->init("/wallpaperPAL.jpg");
360 #else
361     wallpaper_pict->init("wallpaperPAL.jpg");
362 #endif
363   }
364   else
365   {
366     logger->debug(TAG, "NTSC wallpaper selected");
367     wallpaper_pict->init("/wallpaperNTSC.jpg");
368   }
369
370   if (DrawStyle::WALLPAPER.alpha)
371     wallpaper_pict->setVisible(true);
372   else
373     wallpaper_pict->setVisible(false);
374
375   wallpaper->add(wallpaper_pict);
376   wallpaper->draw();
377
378   boxstack->add(wallpaper);
379   boxstack->update(wallpaper);
380
381   OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
382   if (osdv) osdv->updateBackgroundColor(DrawStyle::WALLPAPER);
383 }
384
385 void Control::run()
386 {
387   if (!initted) return;
388   irun = true;
389
390   // just in case
391   Video::getInstance()->signalOn();
392   Led::getInstance()->on();
393
394   doWallpaper();
395
396   if (crashed)
397   {
398     buildCrashedBox();
399   }
400   else
401   {
402     VConnect* vconnect = new VConnect(); // Deleted when VConnect messages Control, and is boxstack->remove()'d
403     boxstack->add(vconnect);
404     vconnect->run();
405   }
406
407   std::unique_lock<std::mutex> lockWrapper(messageQueueMutex);  // locks. unlocks on out-of-scope
408
409   inputMan->start();
410
411   while(irun)
412   {
413     messageQueueCond.wait(lockWrapper, [&] { return !irun || !messages.empty(); });
414     logger->debug(TAG, "woke");
415
416     if (!irun) break;
417
418     while(!messages.empty())
419     {
420       Message* m = messages.front();
421       messages.pop_front();
422
423       lockWrapper.unlock();
424
425       processMessage(m);
426       delete m;
427
428       lockWrapper.lock();
429     }
430   }
431
432   inputMan->stop();
433
434   boxstack->removeAllExceptWallpaper();
435   boxstack->remove(wallpaper);
436   delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
437 }
438
439 void Control::processMessage(Message* m)
440 {
441   logger->debug(TAG, "processing message {}", m->message);
442
443   if (m->p_to == Message::CONTROL)
444   {
445     switch(m->message)
446     {
447       case Message::SHUTDOWN:
448       {
449         irun = false;
450         break;
451       }
452       case Message::STOP_PLAYBACK:
453       {
454         handleCommand(Input::STOP); // an odd way of doing it, but so simple
455         break;
456       }
457       case Message::VDR_CONNECTED:
458       {
459         doJustConnected(static_cast<VConnect*>(m->from));
460         break;
461       }
462       case Message::SCREENSHOT:
463       {
464         logger->info(TAG, "Screenshot Message arrived");
465         Osd::getInstance()->screenShot("out.jpg");
466         break;
467       }
468       case Message::CONNECTION_LOST:
469       {
470         doFromTheTop(true);
471         break;
472       }
473       case Message::INPUT_EVENT:
474       {
475         logger->info(TAG, "INPUT_EVENT {}", m->parameter);
476
477         handleCommand(m->parameter);
478         break;
479       }
480       case Message::CHANGE_LANGUAGE:
481       {
482         boxstack->removeAllExceptWallpaper();
483         boxstack->update(wallpaper);
484         I18n::initialize();
485         if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
486         VWelcome* vw = new VWelcome();
487         vw->draw();
488         boxstack->add(vw);
489         boxstack->update(vw);
490         break;
491       }
492       case Message::LAST_VIEW_CLOSE:
493       {
494         // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
495         if (crashed)
496         {
497           crashed = false;
498           doFromTheTop(false);        
499         }
500       
501 //        VWelcome* vw = new VWelcome();
502 //        vw->draw();
503 //        boxstack->add(vw);
504 //        boxstack->update(vw);
505
506         break;
507       }
508       case Message::NEW_PICTURE:
509       {
510         // FIXME MQSUB
511
512         //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE");
513         OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
514         if (osdv) osdv->informPicture(m->tag, reinterpret_cast<ImageIndex>(m->data));
515         break;
516       }
517       case Message::NEW_PICTURE_STATIC:
518       {
519         //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE %x %x",m->tag,m->parameter);
520         OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
521         if (osdv) osdv->informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<ImageIndex>(m->data));
522         break;
523       }
524     }
525   }
526   else
527   {
528     /* FIXME
529     
530     Instead of sending through the boxstack, implement a more generic MessageReceiver interface
531     and have potential receivers register with something
532     When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
533     This could all be done using the existing big control mutex to keep it simple
534     */
535   
536     logger->debug(TAG, "Sending message to boxstack");
537     boxstack->processMessage(m);
538   }
539 }
540
541 void Control::handleCommand(int button)
542 {
543   if (isStandby && (button != Input::POWER)
544                 && (button != Input::POWERON)
545                 && (button != Input::POWEROFF))  return;
546
547   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
548
549   // command was not handled
550
551   switch(button)
552   {
553     case Input::VOLUMEUP:
554     case Input::VOLUMEDOWN:
555     {
556       if (inputMan->handlesVolume()) // CEC volume handler?
557       {
558         if (button == Input::VOLUMEDOWN)
559           inputMan->volumeDown();
560         else
561           inputMan->volumeUp();
562       }
563       else
564       {
565         VVolume* v = new VVolume();
566         boxstack->add(v);
567         v->handleCommand(button); // this will draw+show
568       }
569       return;
570     }
571     case Input::MUTE:
572     {
573       if (inputMan->handlesVolume())
574       {
575         inputMan->volumeMute();
576       }
577       else
578       {
579         VMute* v = new VMute();
580         v->draw();
581         boxstack->add(v);
582         boxstack->update(v);
583       }
584       return;
585     }
586     case Input::POWER:
587     {
588       doStandby();
589       return;
590     }
591     case Input::POWERON:
592     {
593       doPowerOn();
594       return;
595     }
596     case Input::POWEROFF:
597     {
598       doPowerOff();
599       return;
600     }
601     case Input::OK:
602     {
603       // FIXME
604       if (!connLost) return; // if connLost, handle Input::OK
605       doFromTheTop(false);
606       return;
607     }
608     case Input::GO:
609     {
610       logger->debug(TAG, "Handling sleeptimer go");
611       sleepTimer->go();
612       return;
613     }
614   }
615 }
616
617 /*
618 void Control::sig1()
619 {
620 #ifdef DEV
621   Message* m = new Message(); // break into master mutex
622   m->message = Message::SCREENSHOT;
623   m->p_to = Message::CONTROL;
624   postMessage(m);
625 #endif
626 }
627 */
628
629 void Control::doStandby()
630 {
631   if (isStandby)
632   {
633     doPowerOn();
634   }
635   else
636   {
637     doPowerOff();
638   }
639 }
640
641
642 void Control::doPowerOn()
643 {
644   if (isStandby)
645   {
646     Video::getInstance()->signalOn();
647     Led::getInstance()->on();
648     InputMan::getInstance()->changePowerState(true);
649     isStandby = false;
650
651     VConnect* vconnect = new VConnect();
652     boxstack->add(vconnect);
653     vconnect->run();
654   }
655 }
656
657 void Control::doPowerOff()
658 {
659   if (!isStandby)
660   {
661     VDR::getInstance()->shutdownVDR();
662     boxstack->removeAllExceptWallpaper();
663     Video::getInstance()->signalOff();
664     boxstack->update(wallpaper);
665
666     VDR::getInstance()->configSave("General", "Last Power State", "Off");
667     logger->unsetExternLogger();
668     VDR::getInstance()->disconnect();
669     Led::getInstance()->off();
670     InputMan::getInstance()->changePowerState(false);
671     isStandby = true;
672     sleepTimer->shutdown();
673   }
674 }
675
676 void Control::doFromTheTop(bool which)
677 {
678   if (isStandby) return;
679   if (which)
680   {
681     if (connLost)
682     {
683       logger->info(TAG, "Connection lost dialog already present");
684       return;
685     }
686   
687     logger->info(TAG, "Doing connection lost dialog");
688     connLost = new VInfo();
689     connLost->setSize(360, 200);
690     connLost->createBuffer();
691     if (Video::getInstance()->getFormat() == Video::PAL)
692       connLost->setPosition(190, 170);
693     else
694       connLost->setPosition(180, 120);
695     connLost->setOneLiner(tr("Connection lost"));
696     connLost->setDropThrough();
697     connLost->setBorderOn(1);
698     connLost->setTitleBarColour(DrawStyle::DANGER);
699     connLost->okButton();
700     connLost->draw();
701     boxstack->add(connLost);
702     boxstack->update(connLost);
703
704     clearMQInputEvents();
705   }
706   else
707   {
708     logger->unsetExternLogger();
709     VDR::getInstance()->disconnect();
710     boxstack->removeAllExceptWallpaper();
711     boxstack->update(wallpaper);
712     connLost = NULL;
713     
714     flushMessageQueue();
715     
716     // at this point, everything should be reset to first-go
717     
718     VConnect* vconnect = new VConnect(); // deleted eventually in boxstack
719     boxstack->add(vconnect);
720     vconnect->run();
721   }
722 }
723
724 void Control::clearMQInputEvents()
725 {
726   std::lock_guard<std::mutex> lg(messageQueueMutex); // Get the lock
727
728   MQueueI i = messages.begin();
729   while(i != messages.end())
730   {
731     Message* m = *i;
732     if (m->message == Message::INPUT_EVENT)
733     {
734       delete m;
735       i = messages.erase(i);
736     }
737     else
738     {
739       ++i;
740     }
741   }
742 }
743
744 void Control::doReboot()
745 {
746
747   logger->unsetExternLogger();
748   VDR::getInstance()->disconnect();
749   // just kill it...
750   logger->info(TAG, "Reboot");
751 #ifndef WIN32
752 #ifndef VOMP_HAS_EXIT
753   // some plattforms, want a proper deinitialisation of their hardware before reboot
754   Osd::getInstance()->shutdown();
755   Audio::getInstance()->shutdown();
756   Video::getInstance()->shutdown();
757   InputMan::getInstance()->shutdown();
758
759   reboot(LINUX_REBOOT_CMD_RESTART);
760   // if  reboot is not allowed -> stop
761   stop();
762
763
764 #else
765   stop();
766
767 #ifdef __ANDROID__
768   exit(0);
769 #endif
770
771 #endif
772 #endif //Would we support this on windows?
773 }
774
775 void Control::connectionLost()
776 {
777   logger->unsetExternLogger();
778   Message* m = new Message(); // break into master mutex
779   m->message = Message::CONNECTION_LOST;
780   m->p_to = Message::CONTROL;
781   postMessage(m);
782 }
783
784 void Control::buildCrashedBox()
785 {
786   VInfo* crash = new VInfo();
787   crash->setSize(360, 250);
788   crash->createBuffer();
789   if (Video::getInstance()->getFormat() == Video::PAL)
790     crash->setPosition(190, 146);
791   else
792     crash->setPosition(180, 96);
793   crash->setMainText("Oops, vomp crashed.. :(\nPlease report this crash to the author, with as much detail as possible about what you were doing at the time that might have caused the crash.");
794   crash->setBorderOn(1);
795   crash->setTitleBarColour(DrawStyle::DANGER);
796   crash->okButton();
797   crash->setExitable();
798   crash->draw();
799   boxstack->add(crash);
800   boxstack->update(crash);
801 }
802
803 int Control::getLangPref(bool subtitle, const char* langcode)
804 {
805   std::vector<struct ASLPref>::iterator itty=langcodes.begin();
806   char templangcode[4];
807   templangcode[0] = langcode[0];
808   templangcode[1] = langcode[1];
809   templangcode[2] = langcode[2];
810   templangcode[3] = '\0';
811   int langpos = 0;
812   while (itty != langcodes.end())
813   {
814     size_t pos = (*itty).langcode.find(templangcode);
815     if (pos != std::string::npos)
816     {
817       //vector<struct ASLPref>::iterator itty2=langcodes.begin();
818       for (unsigned int i = 0; i < langcodes.size(); i++)
819       {
820         int pref = 0;
821         if (subtitle)
822           pref = langcodes[i].subtitlepref;
823         else
824           pref = langcodes[i].audiopref;
825         if (pref < 0) break;
826
827         if (subtitle)
828         {
829           if (langcodes[i].subtitlepref==langpos) return i;
830         }
831         else
832         {
833           if (langcodes[i].audiopref==langpos) return i;
834         }
835       }
836       break;
837     }
838     itty++;
839     langpos++;
840   }
841   return langcodes.size(); //neutral
842 }
843
844 void Control::doJustConnected(VConnect* vconnect)
845 {
846   I18n::initialize();
847   if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
848   logger->info(TAG, "Entering doJustConnected");
849   
850   boxstack->remove(vconnect);
851
852   VInfo* vi = new VInfo();
853   vi->setSize(400, 200);
854   vi->createBuffer();
855   if (video->getFormat() == Video::PAL)
856     vi->setPosition(170, 200);
857   else
858     vi->setPosition(160, 150);
859   vi->setOneLiner(tr("Connected, loading config"));
860   vi->draw();
861   boxstack->add(vi);
862   boxstack->update(vi);
863
864   // FIXME make config system
865
866   char* config;
867
868   // See if we're supposed to do network logging
869   config = vdr->configLoad("Advanced", "Network logging");
870   if (config && !STRCASECMP(config, "On"))
871   {
872     logger->info(TAG, "Turning on network logging");
873     logger->setExternLogger(vdr);
874   }  
875   else
876   {
877           logger->unsetExternLogger();
878     logger->info(TAG, "Turned off network logging");
879   }
880   if (config) delete[] config;
881
882   config = vdr->configLoad("Advanced", "Skin Name");
883   if (config)
884   {
885     const char **skinnames=SkinFactory::getSkinNames();
886     for (int i=0;i<SkinFactory::getNumberofSkins();i++)
887     {
888       if (!STRCASECMP(config, skinnames[i]))
889       {
890         SkinFactory::InitSkin(i);
891         break;
892       }
893     }
894     delete[] config;
895
896     if (wallpaper && wallpaper_pict)
897     {
898       if (DrawStyle::WALLPAPER.alpha)
899         wallpaper_pict->setVisible(true);
900       else
901         wallpaper_pict->setVisible(false);
902
903       wallpaper->draw();
904       boxstack->update(wallpaper);
905     }
906   }
907   else
908   {
909     SkinFactory::InitSkin(0);
910   }
911
912   // See if config says to override video format (PAL/NTSC)
913   config = vdr->configLoad("General", "Override Video Format");
914   if (config)
915   {
916     logger->debug(TAG, "Override Video Format is present");
917
918     if (   (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
919         || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
920         || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
921         || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
922         )
923     {
924       // Oh sheesh, need to switch format. Bye bye TV...
925
926       // Take everything down
927       boxstack->removeAllExceptWallpaper();
928       boxstack->remove(wallpaper);
929       delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
930
931 #ifndef __ANDROID__
932       osd->shutdown();
933 #endif
934       video->shutdown();
935
936       inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully
937       inputMan->init(); // FIXME this breaks badly now
938
939       // Get video and osd back up with the new mode
940       if (!strcmp(config, "PAL"))
941       {
942         logger->debug(TAG, "Switching to PAL");
943         video->init(Video::PAL);
944       }
945       else if (!strcmp(config, "NTSC"))
946       {
947         logger->debug(TAG, "Switching to NTSC");
948         video->init(Video::NTSC);
949       } else if (!strcmp(config, "PAL_M"))
950       {
951         logger->debug(TAG, "Switching to PAL_M");
952         video->init(Video::PAL_M);
953       } else if (!strcmp(config, "NTSC_J"))
954       {
955         logger->debug(TAG, "Switching to NTSC_J");
956         video->init(Video::NTSC_J);
957       }
958       delete[] config;
959
960 #ifndef __ANDROID__
961       //we do not init twice
962       osd->init();
963 #endif
964
965       // Put the wallpaper back
966       doWallpaper();
967
968       // Re add the vinfo
969       vi = new VInfo();
970       vi->setSize(400, 200);
971       vi->createBuffer();
972       if (video->getFormat() == Video::PAL)
973         vi->setPosition(170, 200);
974       else
975         vi->setPosition(160, 150);
976
977       vi->setOneLiner(tr("Connected, loading config"));
978       vi->draw();
979       boxstack->add(vi);
980       boxstack->update(vi);
981     }
982     else
983     {
984       logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
985     }
986   }
987   else
988   {
989     logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!");
990   }
991
992   // Power off if first boot and config says so
993   if (firstBoot)
994   {
995     firstBoot = false;
996
997     logger->debug(TAG, "Load power after boot");
998
999     config = vdr->configLoad("General", "Power After Boot");
1000
1001     if (config)
1002     {
1003       if (!STRCASECMP(config, "On"))
1004       {
1005         logger->info(TAG, "Config says Power After Boot = On");
1006       }
1007       else if (!STRCASECMP(config, "Off"))
1008       {
1009         logger->info(TAG, "Config says Power After Boot = Off");
1010         doStandby();
1011         delete[] config;
1012         return; // quit here
1013       }
1014       else if (!STRCASECMP(config, "Last state"))
1015       {
1016         char* lastPowerState = vdr->configLoad("General", "Last Power State");
1017         if (lastPowerState)
1018         {
1019           if (!STRCASECMP(lastPowerState, "On"))
1020           {
1021             logger->info(TAG, "Config says Last Power State = On");
1022           }
1023           else if (!STRCASECMP(lastPowerState, "Off"))
1024           {
1025             logger->info(TAG, "Config says Last Power State = Off");
1026             doStandby();
1027             delete[] config;
1028             return; // quit here
1029           }
1030           else
1031           {
1032             logger->info(TAG, "Config General/Last Power State not understood");
1033           }
1034         }
1035         else
1036         {
1037           logger->info(TAG, "Config General/Last Power State not found");
1038         }
1039       }
1040       else
1041       {
1042         logger->info(TAG, "Config/Power After Boot not understood");
1043       }
1044       delete[] config;
1045     }
1046     else
1047     {
1048       logger->info(TAG, "Config General/Power After Boot not found");
1049     }
1050   }
1051
1052
1053   // Go S-Video if config says so
1054
1055   config = vdr->configLoad("TV", "Connection");
1056
1057   if (config)
1058   {
1059     if (!STRCASECMP(config, "S-Video"))
1060     {
1061       logger->info(TAG, "Switching to S-Video as Connection={}", config);
1062       video->setConnection(Video::SVIDEO);
1063     } else  if (!STRCASECMP(config, "HDMI"))
1064     {
1065       logger->info(TAG, "Switching to HDMI as Connection={}", config);
1066       video->setConnection(Video::HDMI);
1067     } else  if (!STRCASECMP(config, "HDMI3D"))
1068     {
1069       logger->info(TAG, "Switching to HDMI3D as Connection={}", config);
1070       video->setConnection(Video::HDMI3D);
1071     }
1072     else
1073     {
1074       logger->info(TAG, "Switching to RGB/Composite as Connection={}", config);
1075       video->setConnection(Video::COMPOSITERGB);
1076     }
1077     delete[] config;
1078   }
1079   else
1080   {
1081     logger->info(TAG, "Config TV/S-Video not found");
1082   }
1083
1084   // Set to shutdown VDR if config says
1085   
1086   config = vdr->configLoad("General", "VDR shutdown");
1087   if (config)
1088   {
1089     if (!STRCASECMP(config, "On"))
1090     {
1091       logger->info(TAG, "Shutdown VDR when shutting down vomp");
1092       vdr->setVDRShutdown(true);
1093     }
1094     else if (!STRCASECMP(config, "Off"))
1095     {
1096       logger->info(TAG, "Shutdown only vomp");
1097       vdr->setVDRShutdown(false);
1098     }
1099   }
1100   else
1101   {
1102     logger->info(TAG, "Default shutdown only vomp");
1103     vdr->setVDRShutdown(false); // Default
1104   }
1105           
1106   // Get TV aspect ratio
1107
1108   config = vdr->configLoad("TV", "Aspect");
1109   if (config)
1110   {
1111     if (!STRCASECMP(config, "16:9"))
1112     {
1113       logger->info(TAG, "/// Switching to TV aspect 16:9");
1114       video->setTVsize(Video::ASPECT16X9);
1115     }
1116     else
1117     {
1118       logger->info(TAG, "/// Switching to TV aspect 4:3");
1119       video->setTVsize(Video::ASPECT4X3);
1120     }
1121     delete[] config;
1122   }
1123   else
1124   {
1125     logger->info(TAG, "Config TV/Aspect type not found, going 4:3");
1126     video->setTVsize(Video::ASPECT4X3);
1127   }
1128
1129   config = vdr->configLoad("TV", "Widemode");
1130   if (config)
1131   {
1132     if (!STRCASECMP(config, "Letterbox"))
1133     {
1134       logger->info(TAG, "Setting letterbox mode");
1135       video->setMode(Video::LETTERBOX);
1136     }
1137     else
1138     {
1139       logger->info(TAG, "Setting chop-sides mode");
1140       video->setMode(Video::NORMAL);
1141     }
1142     delete[] config;
1143   }
1144   else
1145   {
1146 #ifdef __ANDROID__
1147          logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode");
1148          video->setMode(Video::LETTERBOX);
1149 #else
1150     logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode");
1151     video->setMode(Video::NORMAL);
1152 #endif
1153   }
1154
1155   config = vdr->configLoad("Advanced", "TCP receive window");
1156   if (config)
1157   {
1158     size_t newTCPsize = atoi(config);
1159     delete[] config;
1160
1161     logger->info(TAG, "Setting TCP window size %i", newTCPsize);
1162     vdr->setReceiveWindow(newTCPsize);
1163   }
1164   else
1165   {
1166     logger->info(TAG, "TCP window size not found, setting 2048");
1167     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1168   }
1169
1170   config = vdr->configLoad("Advanced", "Font Name");
1171   if (config)
1172   {
1173         Osd::getInstance()->setFont(config);
1174     logger->info(TAG, "Setting Font to %s", config);
1175     delete[] config;
1176
1177   }
1178
1179
1180   // Set recording list type
1181
1182 #ifdef ADVANCED_MENUES
1183   config = vdr->configLoad("Advanced", "Menu type");
1184
1185   if (config)
1186   {
1187     if (!STRCASECMP(config, "Advanced"))
1188     {
1189       logger->info(TAG, "Switching to Advanced menu");
1190       advMenus = true;
1191     }
1192     else
1193     {
1194       logger->info(TAG, "Switching to Classic menu");
1195       advMenus = false;
1196     }
1197     delete[] config;
1198   }
1199   else
1200   {
1201     logger->info(TAG, "Config General/menu type not found");
1202     advMenus = true;
1203   }
1204 #endif
1205
1206   config = vdr->configLoad("Advanced", "Disable WOL");
1207   if (config)
1208   {
1209     if (!STRCASECMP(config, "Yes"))
1210     {
1211       logger->info(TAG, "Config says disable WOL");
1212       Wol::getInstance()->setEnabled(false);
1213     }
1214     else
1215     {
1216       logger->info(TAG, "Config says enable WOL");
1217       Wol::getInstance()->setEnabled(true);
1218     }
1219
1220     delete[] config;
1221   }
1222   else
1223   {
1224     logger->info(TAG, "By default, enable WOL");
1225     Wol::getInstance()->setEnabled(true);
1226   }
1227   /* device dependend config */
1228   audio->loadOptionsFromServer(vdr);
1229   video->loadOptionsFromServer(vdr);
1230   inputMan->loadOptionsFromServer(vdr);
1231
1232   video->executePendingModeChanges();
1233   // config done
1234
1235   // Save power state = on
1236
1237   vdr->configSave("General", "Last Power State", "On");
1238
1239   // Make sure connection didn't die
1240   if (!vdr->isConnected())
1241   {
1242     Control::getInstance()->connectionLost();
1243   }
1244   else
1245   {
1246     boxstack->remove(vi);
1247
1248     VWelcome* vw = new VWelcome();
1249     vw->draw();
1250     boxstack->add(vw);
1251     boxstack->update(vw);
1252
1253     // Enter pre-keys here
1254 //    handleCommand(Input::OK);
1255 //    handleCommand(Input::THREE);
1256 //    handleCommand(Input::SIX);
1257 //    handleCommand(Input::UP);
1258 //    handleCommand(Input::OK);
1259 //    handleCommand(Input::OK);
1260 //    handleCommand(Input::PLAY);
1261 //    handleCommand(Input::DOWN);
1262 //    handleCommand(Input::DOWN);
1263 //    handleCommand(Input::DOWN);
1264 //    handleCommand(Input::RIGHT);
1265 //    handleCommand(Input::RED);
1266   }
1267 }