]> git.vomp.tv Git - vompclient.git/blob - control.cc
Restructure messages to go direct to target rather than through BoxStack
[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
389   // just in case
390   Video::getInstance()->signalOn();
391   Led::getInstance()->on();
392
393   doWallpaper();
394
395   if (crashed)
396   {
397     buildCrashedBox();
398   }
399   else
400   {
401     VConnect* vconnect = new VConnect(); // Deleted when VConnect messages Control, and is boxstack->remove()'d
402     boxstack->add(vconnect);
403     vconnect->run();
404   }
405
406   inputMan->start();
407
408   messageLoopRun = true;
409   messageLoop();
410
411   inputMan->stop();
412
413   boxstack->removeAllExceptWallpaper();
414   boxstack->remove(wallpaper);
415   delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
416 }
417
418 void Control::dispatchMessage(Message* m)
419 {
420   logger->debug(TAG, "processing message {}", m->message);
421
422   if (m->p_to == Message::CONTROL)
423   {
424     switch(m->message)
425     {
426       case Message::SHUTDOWN:
427       {
428         messageLoopRun = false;
429         break;
430       }
431       case Message::STOP_PLAYBACK:
432       {
433         handleCommand(Input::STOP); // an odd way of doing it, but so simple
434         break;
435       }
436       case Message::VDR_CONNECTED:
437       {
438         doJustConnected(static_cast<VConnect*>(m->from));
439         break;
440       }
441       case Message::SCREENSHOT:
442       {
443         logger->info(TAG, "Screenshot Message arrived");
444         Osd::getInstance()->screenShot("out.jpg");
445         break;
446       }
447       case Message::CONNECTION_LOST:
448       {
449         doFromTheTop(true);
450         break;
451       }
452       case Message::INPUT_EVENT:
453       {
454         logger->info(TAG, "INPUT_EVENT {}", m->parameter);
455
456         handleCommand(m->parameter);
457         break;
458       }
459       case Message::CHANGE_LANGUAGE:
460       {
461         boxstack->removeAllExceptWallpaper();
462         boxstack->update(wallpaper);
463         I18n::initialize();
464         if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
465         VWelcome* vw = new VWelcome();
466         vw->draw();
467         boxstack->add(vw);
468         boxstack->update(vw);
469         break;
470       }
471       case Message::LAST_VIEW_CLOSE:
472       {
473         // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
474         if (crashed)
475         {
476           crashed = false;
477           doFromTheTop(false);        
478         }
479       
480 //        VWelcome* vw = new VWelcome();
481 //        vw->draw();
482 //        boxstack->add(vw);
483 //        boxstack->update(vw);
484
485         break;
486       }
487       case Message::NEW_PICTURE:
488       {
489         // FIXME MQSUB
490
491         //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE");
492         OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
493         if (osdv) osdv->informPicture(m->tag, reinterpret_cast<ImageIndex>(m->data));
494         break;
495       }
496       case Message::NEW_PICTURE_STATIC:
497       {
498         //Log::getInstance()->log("Control", Log::DEBUG, "TVMedia NEW_PICTURE %x %x",m->tag,m->parameter);
499         OsdVector* osdv = dynamic_cast<OsdVector*>(Osd::getInstance());
500         if (osdv) osdv->informPicture(static_cast<unsigned long long>(m->tag) << 32LL, reinterpret_cast<ImageIndex>(m->data));
501         break;
502       }
503     }
504   }
505   else if (m->p_to == Message::BOXSTACK)
506   {
507     boxstack->processMessage(m);
508   }
509   else if (m->p_to == Message::MOUSE_RECEIVER)
510   {
511     logger->debug(TAG, "Sending mouse message to boxstack for dispatch");
512     boxstack->processMessage(m);
513   }
514
515   else
516   {
517     m->to->processMessage(m);
518   }
519
520   logger->debug(TAG, "done processing message {}", m->message);
521 }
522
523 void Control::handleCommand(int button)
524 {
525   if (isStandby && (button != Input::POWER)
526                 && (button != Input::POWERON)
527                 && (button != Input::POWEROFF))  return;
528
529   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
530
531   // command was not handled
532
533   switch(button)
534   {
535     case Input::VOLUMEUP:
536     case Input::VOLUMEDOWN:
537     {
538       if (inputMan->handlesVolume()) // CEC volume handler?
539       {
540         if (button == Input::VOLUMEDOWN)
541           inputMan->volumeDown();
542         else
543           inputMan->volumeUp();
544       }
545       else
546       {
547         VVolume* v = new VVolume();
548         boxstack->add(v);
549         v->handleCommand(button); // this will draw+show
550       }
551       return;
552     }
553     case Input::MUTE:
554     {
555       if (inputMan->handlesVolume())
556       {
557         inputMan->volumeMute();
558       }
559       else
560       {
561         VMute* v = new VMute();
562         v->draw();
563         boxstack->add(v);
564         boxstack->update(v);
565       }
566       return;
567     }
568     case Input::POWER:
569     {
570       doStandby();
571       return;
572     }
573     case Input::POWERON:
574     {
575       doPowerOn();
576       return;
577     }
578     case Input::POWEROFF:
579     {
580       doPowerOff();
581       return;
582     }
583     case Input::OK:
584     {
585       // FIXME
586       if (!connLost) return; // if connLost, handle Input::OK
587       doFromTheTop(false);
588       return;
589     }
590     case Input::GO:
591     {
592       logger->debug(TAG, "Handling sleeptimer go");
593       sleepTimer->go();
594       return;
595     }
596   }
597 }
598
599 /*
600 void Control::sig1()
601 {
602 #ifdef DEV
603   Message* m = new Message(); // break into master mutex
604   m->message = Message::SCREENSHOT;
605   m->p_to = Message::CONTROL;
606   postMessage(m);
607 #endif
608 }
609 */
610
611 void Control::doStandby()
612 {
613   if (isStandby)
614   {
615     doPowerOn();
616   }
617   else
618   {
619     doPowerOff();
620   }
621 }
622
623
624 void Control::doPowerOn()
625 {
626   if (isStandby)
627   {
628     Video::getInstance()->signalOn();
629     Led::getInstance()->on();
630     InputMan::getInstance()->changePowerState(true);
631     isStandby = false;
632
633     VConnect* vconnect = new VConnect();
634     boxstack->add(vconnect);
635     vconnect->run();
636   }
637 }
638
639 void Control::doPowerOff()
640 {
641   if (!isStandby)
642   {
643     VDR::getInstance()->shutdownVDR();
644     boxstack->removeAllExceptWallpaper();
645     Video::getInstance()->signalOff();
646     boxstack->update(wallpaper);
647
648     VDR::getInstance()->configSave("General", "Last Power State", "Off");
649     logger->unsetExternLogger();
650     VDR::getInstance()->disconnect();
651     Led::getInstance()->off();
652     InputMan::getInstance()->changePowerState(false);
653     isStandby = true;
654     sleepTimer->shutdown();
655   }
656 }
657
658 void Control::doFromTheTop(bool which)
659 {
660   if (isStandby) return;
661   if (which)
662   {
663     if (connLost)
664     {
665       logger->info(TAG, "Connection lost dialog already present");
666       return;
667     }
668   
669     logger->info(TAG, "Doing connection lost dialog");
670     connLost = new VInfo();
671     connLost->setSize(360, 200);
672     connLost->createBuffer();
673     if (Video::getInstance()->getFormat() == Video::PAL)
674       connLost->setPosition(190, 170);
675     else
676       connLost->setPosition(180, 120);
677     connLost->setOneLiner(tr("Connection lost"));
678     connLost->setDropThrough();
679     connLost->setBorderOn(1);
680     connLost->setTitleBarColour(DrawStyle::DANGER);
681     connLost->okButton();
682     connLost->draw();
683     boxstack->add(connLost);
684     boxstack->update(connLost);
685
686     clearMQInputEvents();
687   }
688   else
689   {
690     logger->unsetExternLogger();
691     VDR::getInstance()->disconnect();
692     boxstack->removeAllExceptWallpaper();
693     boxstack->update(wallpaper);
694     connLost = NULL;
695     
696     flushMessageQueue();
697     
698     // at this point, everything should be reset to first-go
699     
700     VConnect* vconnect = new VConnect(); // deleted eventually in boxstack
701     boxstack->add(vconnect);
702     vconnect->run();
703   }
704 }
705
706 void Control::clearMQInputEvents()
707 {
708   std::lock_guard<std::mutex> lg(messageQueueMutex); // Get the lock
709
710   MQueueI i = messages.begin();
711   while(i != messages.end())
712   {
713     Message* m = *i;
714     if (m->message == Message::INPUT_EVENT)
715     {
716       delete m;
717       i = messages.erase(i);
718     }
719     else
720     {
721       ++i;
722     }
723   }
724 }
725
726 void Control::doReboot()
727 {
728
729   logger->unsetExternLogger();
730   VDR::getInstance()->disconnect();
731   // just kill it...
732   logger->info(TAG, "Reboot");
733 #ifndef WIN32
734 #ifndef VOMP_HAS_EXIT
735   // some plattforms, want a proper deinitialisation of their hardware before reboot
736   Osd::getInstance()->shutdown();
737   Audio::getInstance()->shutdown();
738   Video::getInstance()->shutdown();
739   InputMan::getInstance()->shutdown();
740
741   reboot(LINUX_REBOOT_CMD_RESTART);
742   // if  reboot is not allowed -> stop
743   stop();
744
745
746 #else
747   stop();
748
749 #ifdef __ANDROID__
750   exit(0);
751 #endif
752
753 #endif
754 #endif //Would we support this on windows?
755 }
756
757 void Control::connectionLost()
758 {
759   logger->unsetExternLogger();
760   Message* m = new Message(); // break into master mutex
761   m->message = Message::CONNECTION_LOST;
762   m->p_to = Message::CONTROL;
763   postMessage(m);
764 }
765
766 void Control::buildCrashedBox()
767 {
768   VInfo* crash = new VInfo();
769   crash->setSize(360, 250);
770   crash->createBuffer();
771   if (Video::getInstance()->getFormat() == Video::PAL)
772     crash->setPosition(190, 146);
773   else
774     crash->setPosition(180, 96);
775   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.");
776   crash->setBorderOn(1);
777   crash->setTitleBarColour(DrawStyle::DANGER);
778   crash->okButton();
779   crash->setExitable();
780   crash->draw();
781   boxstack->add(crash);
782   boxstack->update(crash);
783 }
784
785 int Control::getLangPref(bool subtitle, const char* langcode)
786 {
787   std::vector<struct ASLPref>::iterator itty=langcodes.begin();
788   char templangcode[4];
789   templangcode[0] = langcode[0];
790   templangcode[1] = langcode[1];
791   templangcode[2] = langcode[2];
792   templangcode[3] = '\0';
793   int langpos = 0;
794   while (itty != langcodes.end())
795   {
796     size_t pos = (*itty).langcode.find(templangcode);
797     if (pos != std::string::npos)
798     {
799       //vector<struct ASLPref>::iterator itty2=langcodes.begin();
800       for (unsigned int i = 0; i < langcodes.size(); i++)
801       {
802         int pref = 0;
803         if (subtitle)
804           pref = langcodes[i].subtitlepref;
805         else
806           pref = langcodes[i].audiopref;
807         if (pref < 0) break;
808
809         if (subtitle)
810         {
811           if (langcodes[i].subtitlepref==langpos) return i;
812         }
813         else
814         {
815           if (langcodes[i].audiopref==langpos) return i;
816         }
817       }
818       break;
819     }
820     itty++;
821     langpos++;
822   }
823   return langcodes.size(); //neutral
824 }
825
826 void Control::doJustConnected(VConnect* vconnect)
827 {
828   I18n::initialize();
829   if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
830   logger->info(TAG, "Entering doJustConnected");
831   
832   boxstack->remove(vconnect);
833
834   VInfo* vi = new VInfo();
835   vi->setSize(400, 200);
836   vi->createBuffer();
837   if (video->getFormat() == Video::PAL)
838     vi->setPosition(170, 200);
839   else
840     vi->setPosition(160, 150);
841   vi->setOneLiner(tr("Connected, loading config"));
842   vi->draw();
843   boxstack->add(vi);
844   boxstack->update(vi);
845
846   // FIXME make config system
847
848   char* config;
849
850   // See if we're supposed to do network logging
851   config = vdr->configLoad("Advanced", "Network logging");
852   if (config && !STRCASECMP(config, "On"))
853   {
854     logger->info(TAG, "Turning on network logging");
855     logger->setExternLogger(vdr);
856   }  
857   else
858   {
859           logger->unsetExternLogger();
860     logger->info(TAG, "Turned off network logging");
861   }
862   if (config) delete[] config;
863
864   config = vdr->configLoad("Advanced", "Skin Name");
865   if (config)
866   {
867     const char **skinnames=SkinFactory::getSkinNames();
868     for (int i=0;i<SkinFactory::getNumberofSkins();i++)
869     {
870       if (!STRCASECMP(config, skinnames[i]))
871       {
872         SkinFactory::InitSkin(i);
873         break;
874       }
875     }
876     delete[] config;
877
878     if (wallpaper && wallpaper_pict)
879     {
880       if (DrawStyle::WALLPAPER.alpha)
881         wallpaper_pict->setVisible(true);
882       else
883         wallpaper_pict->setVisible(false);
884
885       wallpaper->draw();
886       boxstack->update(wallpaper);
887     }
888   }
889   else
890   {
891     SkinFactory::InitSkin(0);
892   }
893
894   // See if config says to override video format (PAL/NTSC)
895   config = vdr->configLoad("General", "Override Video Format");
896   if (config)
897   {
898     logger->debug(TAG, "Override Video Format is present");
899
900     if (   (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
901         || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
902         || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
903         || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
904         )
905     {
906       // Oh sheesh, need to switch format. Bye bye TV...
907
908       // Take everything down
909       boxstack->removeAllExceptWallpaper();
910       boxstack->remove(wallpaper);
911       delete wallpaper_pict; wallpaper_pict = NULL; wallpaper = NULL;
912
913 #ifndef __ANDROID__
914       osd->shutdown();
915 #endif
916       video->shutdown();
917
918       inputMan->shutdown(); // need on raspberry shut not do any harm, hopefully
919       inputMan->init(); // FIXME this breaks badly now
920
921       // Get video and osd back up with the new mode
922       if (!strcmp(config, "PAL"))
923       {
924         logger->debug(TAG, "Switching to PAL");
925         video->init(Video::PAL);
926       }
927       else if (!strcmp(config, "NTSC"))
928       {
929         logger->debug(TAG, "Switching to NTSC");
930         video->init(Video::NTSC);
931       } else if (!strcmp(config, "PAL_M"))
932       {
933         logger->debug(TAG, "Switching to PAL_M");
934         video->init(Video::PAL_M);
935       } else if (!strcmp(config, "NTSC_J"))
936       {
937         logger->debug(TAG, "Switching to NTSC_J");
938         video->init(Video::NTSC_J);
939       }
940       delete[] config;
941
942 #ifndef __ANDROID__
943       //we do not init twice
944       osd->init();
945 #endif
946
947       // Put the wallpaper back
948       doWallpaper();
949
950       // Re add the vinfo
951       vi = new VInfo();
952       vi->setSize(400, 200);
953       vi->createBuffer();
954       if (video->getFormat() == Video::PAL)
955         vi->setPosition(170, 200);
956       else
957         vi->setPosition(160, 150);
958
959       vi->setOneLiner(tr("Connected, loading config"));
960       vi->draw();
961       boxstack->add(vi);
962       boxstack->update(vi);
963     }
964     else
965     {
966       logger->debug(TAG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
967     }
968   }
969   else
970   {
971     logger->debug(TAG, "Phew, no dangerous on-the-fly mode switching to do!");
972   }
973
974   // Power off if first boot and config says so
975   if (firstBoot)
976   {
977     firstBoot = false;
978
979     logger->debug(TAG, "Load power after boot");
980
981     config = vdr->configLoad("General", "Power After Boot");
982
983     if (config)
984     {
985       if (!STRCASECMP(config, "On"))
986       {
987         logger->info(TAG, "Config says Power After Boot = On");
988       }
989       else if (!STRCASECMP(config, "Off"))
990       {
991         logger->info(TAG, "Config says Power After Boot = Off");
992         doStandby();
993         delete[] config;
994         return; // quit here
995       }
996       else if (!STRCASECMP(config, "Last state"))
997       {
998         char* lastPowerState = vdr->configLoad("General", "Last Power State");
999         if (lastPowerState)
1000         {
1001           if (!STRCASECMP(lastPowerState, "On"))
1002           {
1003             logger->info(TAG, "Config says Last Power State = On");
1004           }
1005           else if (!STRCASECMP(lastPowerState, "Off"))
1006           {
1007             logger->info(TAG, "Config says Last Power State = Off");
1008             doStandby();
1009             delete[] config;
1010             return; // quit here
1011           }
1012           else
1013           {
1014             logger->info(TAG, "Config General/Last Power State not understood");
1015           }
1016         }
1017         else
1018         {
1019           logger->info(TAG, "Config General/Last Power State not found");
1020         }
1021       }
1022       else
1023       {
1024         logger->info(TAG, "Config/Power After Boot not understood");
1025       }
1026       delete[] config;
1027     }
1028     else
1029     {
1030       logger->info(TAG, "Config General/Power After Boot not found");
1031     }
1032   }
1033
1034
1035   // Go S-Video if config says so
1036
1037   config = vdr->configLoad("TV", "Connection");
1038
1039   if (config)
1040   {
1041     if (!STRCASECMP(config, "S-Video"))
1042     {
1043       logger->info(TAG, "Switching to S-Video as Connection={}", config);
1044       video->setConnection(Video::SVIDEO);
1045     } else  if (!STRCASECMP(config, "HDMI"))
1046     {
1047       logger->info(TAG, "Switching to HDMI as Connection={}", config);
1048       video->setConnection(Video::HDMI);
1049     } else  if (!STRCASECMP(config, "HDMI3D"))
1050     {
1051       logger->info(TAG, "Switching to HDMI3D as Connection={}", config);
1052       video->setConnection(Video::HDMI3D);
1053     }
1054     else
1055     {
1056       logger->info(TAG, "Switching to RGB/Composite as Connection={}", config);
1057       video->setConnection(Video::COMPOSITERGB);
1058     }
1059     delete[] config;
1060   }
1061   else
1062   {
1063     logger->info(TAG, "Config TV/S-Video not found");
1064   }
1065
1066   // Set to shutdown VDR if config says
1067   
1068   config = vdr->configLoad("General", "VDR shutdown");
1069   if (config)
1070   {
1071     if (!STRCASECMP(config, "On"))
1072     {
1073       logger->info(TAG, "Shutdown VDR when shutting down vomp");
1074       vdr->setVDRShutdown(true);
1075     }
1076     else if (!STRCASECMP(config, "Off"))
1077     {
1078       logger->info(TAG, "Shutdown only vomp");
1079       vdr->setVDRShutdown(false);
1080     }
1081   }
1082   else
1083   {
1084     logger->info(TAG, "Default shutdown only vomp");
1085     vdr->setVDRShutdown(false); // Default
1086   }
1087           
1088   // Get TV aspect ratio
1089
1090   config = vdr->configLoad("TV", "Aspect");
1091   if (config)
1092   {
1093     if (!STRCASECMP(config, "16:9"))
1094     {
1095       logger->info(TAG, "/// Switching to TV aspect 16:9");
1096       video->setTVsize(Video::ASPECT16X9);
1097     }
1098     else
1099     {
1100       logger->info(TAG, "/// Switching to TV aspect 4:3");
1101       video->setTVsize(Video::ASPECT4X3);
1102     }
1103     delete[] config;
1104   }
1105   else
1106   {
1107     logger->info(TAG, "Config TV/Aspect type not found, going 4:3");
1108     video->setTVsize(Video::ASPECT4X3);
1109   }
1110
1111   config = vdr->configLoad("TV", "Widemode");
1112   if (config)
1113   {
1114     if (!STRCASECMP(config, "Letterbox"))
1115     {
1116       logger->info(TAG, "Setting letterbox mode");
1117       video->setMode(Video::LETTERBOX);
1118     }
1119     else
1120     {
1121       logger->info(TAG, "Setting chop-sides mode");
1122       video->setMode(Video::NORMAL);
1123     }
1124     delete[] config;
1125   }
1126   else
1127   {
1128 #ifdef __ANDROID__
1129          logger->info(TAG, "Config TV/Widemode not found, Setting letterbox mode");
1130          video->setMode(Video::LETTERBOX);
1131 #else
1132     logger->info(TAG, "Config TV/Widemode not found, Setting chop-sides mode");
1133     video->setMode(Video::NORMAL);
1134 #endif
1135   }
1136
1137   config = vdr->configLoad("Advanced", "TCP receive window");
1138   if (config)
1139   {
1140     size_t newTCPsize = atoi(config);
1141     delete[] config;
1142
1143     logger->info(TAG, "Setting TCP window size %i", newTCPsize);
1144     vdr->setReceiveWindow(newTCPsize);
1145   }
1146   else
1147   {
1148     logger->info(TAG, "TCP window size not found, setting 2048");
1149     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1150   }
1151
1152   config = vdr->configLoad("Advanced", "Font Name");
1153   if (config)
1154   {
1155         Osd::getInstance()->setFont(config);
1156     logger->info(TAG, "Setting Font to %s", config);
1157     delete[] config;
1158
1159   }
1160
1161
1162   // Set recording list type
1163
1164 #ifdef ADVANCED_MENUES
1165   config = vdr->configLoad("Advanced", "Menu type");
1166
1167   if (config)
1168   {
1169     if (!STRCASECMP(config, "Advanced"))
1170     {
1171       logger->info(TAG, "Switching to Advanced menu");
1172       advMenus = true;
1173     }
1174     else
1175     {
1176       logger->info(TAG, "Switching to Classic menu");
1177       advMenus = false;
1178     }
1179     delete[] config;
1180   }
1181   else
1182   {
1183     logger->info(TAG, "Config General/menu type not found");
1184     advMenus = true;
1185   }
1186 #endif
1187
1188   config = vdr->configLoad("Advanced", "Disable WOL");
1189   if (config)
1190   {
1191     if (!STRCASECMP(config, "Yes"))
1192     {
1193       logger->info(TAG, "Config says disable WOL");
1194       Wol::getInstance()->setEnabled(false);
1195     }
1196     else
1197     {
1198       logger->info(TAG, "Config says enable WOL");
1199       Wol::getInstance()->setEnabled(true);
1200     }
1201
1202     delete[] config;
1203   }
1204   else
1205   {
1206     logger->info(TAG, "By default, enable WOL");
1207     Wol::getInstance()->setEnabled(true);
1208   }
1209   /* device dependend config */
1210   audio->loadOptionsFromServer(vdr);
1211   video->loadOptionsFromServer(vdr);
1212   inputMan->loadOptionsFromServer(vdr);
1213
1214   video->executePendingModeChanges();
1215   // config done
1216
1217   // Save power state = on
1218
1219   vdr->configSave("General", "Last Power State", "On");
1220
1221   // Make sure connection didn't die
1222   if (!vdr->isConnected())
1223   {
1224     Control::getInstance()->connectionLost();
1225   }
1226   else
1227   {
1228     boxstack->remove(vi);
1229
1230     VWelcome* vw = new VWelcome();
1231     vw->draw();
1232     boxstack->add(vw);
1233     boxstack->update(vw);
1234
1235     // Enter pre-keys here
1236 //    handleCommand(Input::OK);
1237 //    handleCommand(Input::THREE);
1238 //    handleCommand(Input::SIX);
1239 //    handleCommand(Input::UP);
1240 //    handleCommand(Input::OK);
1241 //    handleCommand(Input::OK);
1242 //    handleCommand(Input::PLAY);
1243 //    handleCommand(Input::DOWN);
1244 //    handleCommand(Input::DOWN);
1245 //    handleCommand(Input::DOWN);
1246 //    handleCommand(Input::RIGHT);
1247 //    handleCommand(Input::RED);
1248   }
1249 }