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