]> git.vomp.tv Git - vompclient.git/blob - command.cc
Extended recordings menu, including artwork from tvscraper
[vompclient.git] / command.cc
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #ifndef WIN32
22 #include <linux/errno.h>
23 #endif
24
25 #include "command.h"
26
27 #ifdef WIN32
28 #include "remotewin.h"
29 #endif
30
31 #ifdef __ANDROID__
32 #include "remoteandroid.h"
33 #endif
34
35 #include "led.h"
36 #include "video.h"
37 #include "audio.h"
38 #include "mtd.h"
39 #include "vdr.h"
40 #include "vvolume.h"
41 #include "vserverselect.h"
42 #include "vwelcome.h"
43 #include "vmute.h"
44 #include "colour.h"
45 #include "osd.h"
46 #include "i18n.h"
47 #include "timerreceiver.h"
48 #include "timers.h"
49 #include "wol.h"
50 #include "vconnect.h"
51 #include "message.h"
52 #include "remote.h"
53 #include "vinfo.h"
54 #include "boxx.h"
55 #include "boxstack.h"
56 #include "log.h"
57 #include "vsleeptimer.h"
58
59
60 Command* Command::instance = NULL;
61
62 Command::Command()
63 {
64   if (instance) return;
65   instance = this;
66   initted = 0;
67   isStandby = 0;
68   firstBoot = 1;
69   connLost = NULL;
70   crashed = false;
71   server = NULL;
72 }
73
74 Command::~Command()
75 {
76   instance = NULL;
77 }
78
79 Command* Command::getInstance()
80 {
81   return instance;
82 }
83
84 int Command::init(bool tcrashed, char* tServer)
85 {
86   if (initted) return 0;
87   initted = 1;
88   crashed = tcrashed;
89   server = tServer;
90
91   logger = Log::getInstance();
92   boxstack = BoxStack::getInstance();
93   remote = Remote::getInstance();
94   
95   remote->InitHWCListwithDefaults();
96   
97   if (!logger || !boxstack || !remote)
98   {
99     initted = 0;
100     return 0;
101   }
102 #ifdef GRADIENT_DRAWING
103   SkinFactory::InitEnhancedSkin();
104 #else
105   SkinFactory::InitDefaultSkin();
106 #endif
107
108 #ifndef WIN32
109   pthread_mutex_init(&masterLock, NULL);
110 #else
111   masterLock=CreateMutex(NULL,FALSE,NULL);
112 #endif
113
114   return 1;
115 }
116
117 int Command::shutdown()
118 {
119   if (!initted) return 0;
120   initted = 0;
121   return 1;
122 }
123
124 void Command::stop()
125 {
126 //  VDR::getInstance()->cancelFindingServer();
127         logger->log("Command", Log::NOTICE, "Command stop1...");
128         
129   udp.shutdown();
130   logger->log("Command", Log::NOTICE,  "Command stop2...");
131   irun = 0;
132 }
133
134 void Command::doWallpaper()
135 {
136   Video* video = Video::getInstance();
137
138   // Blue background
139   Boxx* bbg = new Boxx();
140   bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
141   bbg->createBuffer();
142   bbg->fillColour(DrawStyle::VIDEOBLUE);
143   boxstack->add(bbg);
144   boxstack->update(bbg);
145   boxstack->remove(bbg);
146
147   // Wallpaper
148   WJpeg* wallpaperj = new WJpegTYPE();
149   wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
150   wallpaperj->createBuffer();
151
152   if (video->getFormat() == Video::PAL)
153   {
154     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
155 #ifndef _MIPS_ARCH    
156     wallpaperj->init("/wallpaperPAL.jpg");
157 #else
158     wallpaperj->init("wallpaperPAL.jpg");
159 #endif
160   }
161   else
162   {
163     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
164     wallpaperj->init("/wallpaperNTSC.jpg");
165   }
166   wallpaperj->draw();
167
168   boxstack->add(wallpaperj);
169   boxstack->update(wallpaperj);
170
171   wallpaper = wallpaperj;
172 }
173
174 void Command::run()
175 {
176   if (!initted) return;
177   irun = 1;
178 #ifndef WIN32
179   mainPid = getpid();
180 #endif
181
182   // just in case
183   Video::getInstance()->signalOn();
184   Led::getInstance()->on();
185
186   doWallpaper();
187
188   // End of startup. Lock the mutex and put the first view up
189 //  logger->log("Command", Log::DEBUG, "WANT LOCK");
190 #ifndef WIN32
191   pthread_mutex_lock(&masterLock);
192 #else
193   WaitForSingleObject(masterLock, INFINITE );
194 #endif
195   //logger->log("Command", Log::DEBUG, "LOCKED");
196
197   if (crashed)
198   {
199     buildCrashedBox();
200   }
201   else
202   {
203     VConnect* vconnect = new VConnect(server);
204     boxstack->add(vconnect);
205     vconnect->run();
206   }
207
208   // Start method 2 of getting commands in...
209   udp.run(this);
210
211   UCHAR button = 0;
212   while(irun)
213   {
214     // unlock and wait
215     //logger->log("Command", Log::DEBUG, "UNLOCK");
216 #ifndef WIN32
217     pthread_mutex_unlock(&masterLock);
218 #else
219     ReleaseMutex(masterLock);
220 #endif
221         
222     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit 
223     // something happened, lock and process
224         
225     //  logger->log("Command", Log::DEBUG, "WANT LOCK");
226 #ifndef WIN32
227     pthread_mutex_lock(&masterLock);
228 #else
229     WaitForSingleObject(masterLock, INFINITE );
230 #endif
231     // logger->log("Command", Log::DEBUG, "LOCK");
232
233     if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
234
235     if (button != Remote::NA_SIGNAL) handleCommand(button);
236     processMessageQueue();
237
238   }
239
240   //logger->log("Command", Log::DEBUG, "UNLOCK");
241 #ifndef WIN32
242   pthread_mutex_unlock(&masterLock);
243 #else
244   ReleaseMutex(masterLock);
245 #endif
246
247
248 }
249
250 void Command::postMessage(Message* m)
251 {
252   // This is locked here in case the main loop is not waiting for an event, but is processing one
253   // it could be killed but then not react to it because the signal wouldn't cause
254   // remote->getButtonPress to break
255   // locking the mutex ensures that the master thread is waiting on getButtonPress
256
257
258   //logger->log("Command", Log::DEBUG, "WANT LOCK");
259 #ifndef WIN32
260   pthread_mutex_lock(&masterLock);
261 #else
262   WaitForSingleObject(masterLock, INFINITE );
263 #endif
264   //logger->log("Command", Log::DEBUG, "LOCK");
265   MessageQueue::postMessage(m);
266
267 #ifndef WIN32
268 #ifndef __ANDROID__
269   kill(mainPid, SIGURG);
270 #else
271   ((RemoteAndroid*)Remote::getInstance())->Signal();
272 #endif
273   pthread_mutex_unlock(&masterLock);
274 #else
275   ((RemoteWin*)Remote::getInstance())->Signal();
276   ReleaseMutex(masterLock);
277 #endif
278   //logger->log("Command", Log::DEBUG, "UNLOCK");
279 }
280
281 void Command::postMessageNoLock(Message* m)
282 {
283   // As above but use this one if this message is being posted because of a button press
284   // the mutex is already locked, locking around postMessage is not needed as the
285   // queue is guaranteed to be run when the button has been processed
286   MessageQueue::postMessage(m);
287 }
288
289 bool Command::postMessageIfNotBusy(Message* m)
290 {
291   // Used for Windows mouse events
292
293   //logger->log("Command", Log::DEBUG, "TRY LOCK");
294 #ifndef WIN32
295   if (pthread_mutex_trylock(&masterLock) != EBUSY)
296   {
297     //logger->log("Command", Log::DEBUG, "LOCK");
298     MessageQueue::postMessage(m);
299 #ifndef __ANDROID__
300     kill(mainPid, SIGURG);
301 #else
302     ((RemoteAndroid*)Remote::getInstance())->Signal();
303 #endif
304     pthread_mutex_unlock(&masterLock);
305     //logger->log("Command", Log::DEBUG, "UNLOCK");
306     return true;
307   }
308   else
309   {
310     return false;
311   }
312 #else
313   switch (WaitForSingleObject(masterLock, 0 ))
314   { //FIXME this is not "if not busy" check
315     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
316     // case WAIT_ABANDONED:
317     MessageQueue::postMessage(m);
318     ((RemoteWin*)Remote::getInstance())->Signal();
319     ReleaseMutex(masterLock);
320     return true;
321
322     case WAIT_ABANDONED: return false;
323     case WAIT_TIMEOUT: return false;
324   }
325     return false;
326 #endif
327 }
328
329 void Command::postMessageFromOuterSpace(Message* m)
330 {
331   /*
332   Yet another way of getting messages into Command. This one is for events that
333   are not standard button presses (or UDP generated buttons). It is also not for
334   events that are generated as a result of other events (events that can safely
335   call postMessageNoLock and be guaranteed that the message will be processed
336   because it is known that the queue is currently being processed).
337   This is for events that come from outer space and can occur when the master
338   mutex is locked or not, they need to be queued and executed but it doesn't
339   matter when.
340   Actually so far it is for events caused by the video stream - aspect ratio
341   changes. These can occur when the master mutex is locked and so postMessage
342   doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
343   locked at the time then the message could be sat around a while before
344   being noticed.
345   The whole message system was at first supposed to prevent the problem of
346   calling a function on an object that had just been deleted, by ordering
347   messages such that all calls are done before object deletion. However,
348   because of the new centralised messaging system and the fact that BoxStack
349   locates the destination object before calling it, the messaging system now
350   allows the kind of sloppy calls it was supposed to stop. Weird huh. This
351   is mentioned here because the video stream might generate an event just as
352   the user hits stop. The mutex is locked, and by the time the message
353   is examined the vvideorec/live has been deleted. This doesn't matter because
354   boxstack will drop the message if it can't find the matching object to
355   deliver it to.
356   Finally, all this is fine and dandy, except that I'm not 100% sure that
357   this sloppy postMessage and hope a queued signal will force it to be processed
358   thingy will actually work. Hmmm.
359   Lastly <g>, I will consider making the naming system a little more sane
360   if this works.
361   */
362
363   logger->log("Command", Log::DEBUG, "PMFOS called");
364   MessageQueue::postMessage(m);
365
366 #ifndef WIN32
367 #ifndef __ANDROID__
368   kill(mainPid, SIGURG);
369 #else
370   ((RemoteAndroid*)Remote::getInstance())->Signal();
371 #endif
372 #else
373   ((RemoteWin*)Remote::getInstance())->Signal();
374 #endif
375 }
376
377 void Command::processMessage(Message* m)
378 {
379     // FIXME - a slight modification - how if messagereceivers were to register
380     // themselves as receivers to avoid the calling-a-deleted-object problem
381     // then only deliver/register/unregister would have to be protected
382
383   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
384
385
386   if (m->to == this)
387   {
388     switch(m->message)
389     {
390       // << FIXME OBSELETE
391       case Message::STOP_PLAYBACK:
392       {
393         handleCommand(Remote::STOP); // an odd way of doing it, but so simple
394         break;
395       }
396       // Also connection_lost comes from player - anywhere else?
397       // FIXME OBSELETE >>
398
399
400       case Message::VDR_CONNECTED:
401       {
402         doJustConnected((VConnect*)m->from);
403         break;
404       }
405       case Message::SCREENSHOT:
406       {
407         Osd::getInstance()->screenShot("/out.jpg");
408         break;
409       }
410       case Message::CONNECTION_LOST:
411       {
412         doFromTheTop(true);
413         break;
414       }
415       case Message::UDP_BUTTON:
416       {
417         handleCommand(m->parameter);
418         break;
419       }
420       case Message::CHANGE_LANGUAGE:
421       {
422         boxstack->removeAll();
423         boxstack->update(wallpaper);
424         I18n::initialize();
425         if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
426         VWelcome* vw = new VWelcome();
427         vw->draw();
428         boxstack->add(vw);
429         boxstack->update(vw);
430         break;
431       }
432       case Message::LAST_VIEW_CLOSE:
433       {
434         // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
435         if (crashed)
436         {
437           crashed = false;
438           doFromTheTop(false);        
439         }
440       
441 //        VWelcome* vw = new VWelcome();
442 //        vw->draw();
443 //        boxstack->add(vw);
444 //        boxstack->update(vw);
445
446         break;
447       }
448       case Message::NEW_PICTURE:
449       {
450           Log::getInstance()->log("Command", Log::DEBUG, "TVMedia NEW_PICTURE");
451           OsdVector *osdv=dynamic_cast<OsdVector*>(Osd::getInstance());
452           if (osdv) {
453                   osdv->informPicture(m->tag,m->parameter);
454           }
455
456       } break;
457     }
458   }
459   else
460   {
461     /* FIXME
462     
463     Instead of sending through the boxstack, implement a more generic MessageReceiver interface
464     and have potential receivers register with something
465     When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
466     This could all be done using the existing big command mutex to keep it simple
467     */
468   
469     logger->log("Command", Log::DEBUG, "Sending message to boxstack");
470     boxstack->processMessage(m);
471   }
472 }
473
474 void Command::handleCommand(int button)
475 {
476   if (isStandby && (button != Remote::POWER) 
477       && (button != Remote::POWERON) && (button != Remote::POWEROFF))  return;
478   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
479
480   // command was not handled
481
482   switch(button)
483   {
484     case Remote::DF_LEFT:
485     case Remote::DF_RIGHT:
486     case Remote::VOLUMEUP:
487     case Remote::VOLUMEDOWN:
488     {
489         if (remote->handlesVolume()) {
490                 if (button==Remote::DF_LEFT || button==Remote::VOLUMEDOWN)
491                         remote->volumeDown();
492                 else remote->volumeUp();
493         } else {
494                 VVolume* v = new VVolume();
495                 boxstack->add(v);
496                 v->handleCommand(button); // this will draw+show
497         }
498       return;
499     }
500     case Remote::MUTE:
501     {
502         if (remote->handlesVolume()) {
503                 remote->volumeMute();
504         } else {
505                 VMute* v = new VMute();
506                 v->draw();
507                 boxstack->add(v);
508                 boxstack->update(v);
509         }
510       return;
511     }
512     case Remote::POWER:
513     {
514       doStandby();
515       return;
516     }
517     case Remote::POWERON:
518     {
519       doPowerOn();
520       return;
521     }
522     case Remote::POWEROFF:
523     {
524       doPowerOff();
525       return;
526     }
527     case Remote::OK:
528     {
529       // FIXME
530       if (!connLost) return; // if connLost, handle Remote::OK
531       doFromTheTop(false);
532       return;
533     }
534     case Remote::GO:
535     {
536       VSleeptimer* sleep = new VSleeptimer();
537       boxstack->add(sleep);
538       sleep->handleCommand(button); // this will draw+show
539       return;
540     }
541   }
542 }
543
544 void Command::sig1()
545 {
546 #ifdef DEV
547   Message* m = new Message(); // break into master mutex
548   m->message = Message::SCREENSHOT;
549   m->to = this;
550   postMessage(m);
551 #endif
552 }
553
554 void Command::doStandby()
555 {
556   if (isStandby)
557   {
558     doPowerOn();
559   }
560   else
561   {
562    doPowerOff();
563   }
564 }
565
566
567 void Command::doPowerOn()
568 {
569   if (isStandby)
570   {
571     Video::getInstance()->signalOn();
572     Led::getInstance()->on();
573     Remote::getInstance()->changePowerState(true);
574     isStandby = 0;
575
576
577     VConnect* vconnect = new VConnect(server);
578     boxstack->add(vconnect);
579     vconnect->run();
580   }
581 }
582
583 void Command::doPowerOff()
584 {
585   if (!isStandby)
586   {
587     VDR::getInstance()->shutdownVDR();
588     boxstack->removeAll();
589     Video::getInstance()->signalOff();
590     boxstack->update(wallpaper);
591
592     VDR::getInstance()->configSave("General", "Last Power State", "Off");
593     logger->unsetExternLogger();
594     VDR::getInstance()->disconnect();
595     Led::getInstance()->off();
596     Remote::getInstance()->changePowerState(false);
597     isStandby = 1;
598     Sleeptimer::getInstance()->shutdown();
599 #ifdef WIN32
600     stop(); //different behavoiur on windows, we exit
601 #endif
602   }
603 }
604
605 void Command::doFromTheTop(bool which)
606 {
607   if (isStandby) return;
608   if (which)
609   {
610     if (connLost)
611     {
612       logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
613       return;
614     }
615   
616     logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
617     connLost = new VInfo();
618     connLost->setSize(360, 200);
619     connLost->createBuffer();
620     if (Video::getInstance()->getFormat() == Video::PAL)
621       connLost->setPosition(190, 170);
622     else
623       connLost->setPosition(180, 120);
624     connLost->setOneLiner(tr("Connection lost"));
625     connLost->setDropThrough();
626     connLost->setBorderOn(1);
627     connLost->setTitleBarColour(DrawStyle::DANGER);
628     connLost->okButton();
629     connLost->draw();
630     boxstack->add(connLost);
631     boxstack->update(connLost);
632     remote->clearBuffer();
633   }
634   else
635   {
636     logger->unsetExternLogger();
637     VDR::getInstance()->disconnect();
638     boxstack->removeAll();
639     boxstack->update(wallpaper);
640     connLost = NULL;
641     
642     flushMessageQueue();
643     remote->clearBuffer();
644     
645     // at this point, everything should be reset to first-go
646     
647     VConnect* vconnect = new VConnect(server);
648     boxstack->add(vconnect);
649     vconnect->run();
650   }
651 }
652
653 void Command::doReboot()
654 {
655
656   logger->unsetExternLogger();
657   VDR::getInstance()->disconnect();
658   // just kill it...
659   logger->log("Command", Log::NOTICE, "Reboot");
660 #ifndef WIN32
661 #ifndef VOMP_HAS_EXIT
662   // some plattforms, want a proper deinitialisation of their hardware before reboot
663   Osd::getInstance()->shutdown();
664   Audio::getInstance()->shutdown();
665   Video::getInstance()->shutdown();
666   Remote::getInstance()->shutdown();
667
668   reboot(LINUX_REBOOT_CMD_RESTART);
669   // if  reboot is not allowed -> stop
670   stop();
671
672
673 #else
674   stop();
675
676 #ifdef __ANDROID__
677   exit(0);
678 #endif
679
680 #endif
681 #endif //Would we support this on windows?
682 }
683
684 void Command::connectionLost()
685 {
686   logger->unsetExternLogger();
687   Message* m = new Message(); // break into master mutex
688   m->message = Message::CONNECTION_LOST;
689   m->to = this;
690   postMessageFromOuterSpace(m);
691 }
692
693 void Command::buildCrashedBox()
694 {
695   VInfo* crash = new VInfo();
696   crash->setSize(360, 250);
697   crash->createBuffer();
698   if (Video::getInstance()->getFormat() == Video::PAL)
699     crash->setPosition(190, 146);
700   else
701     crash->setPosition(180, 96);
702   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.");
703   crash->setBorderOn(1);
704   crash->setTitleBarColour(DrawStyle::DANGER);
705   crash->okButton();
706   crash->setExitable();
707   crash->draw();
708   boxstack->add(crash);
709   boxstack->update(crash);
710 }
711
712 void Command::doJustConnected(VConnect* vconnect)
713 {
714   I18n::initialize();
715   if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
716   logger->log("Command", Log::INFO, "Entering doJustConnected");
717   
718   Video* video = Video::getInstance();
719   Audio* audio = Audio::getInstance();  
720   boxstack->remove(vconnect);
721
722   VInfo* vi = new VInfo();
723   vi->setSize(400, 200);
724   vi->createBuffer();
725   if (video->getFormat() == Video::PAL)
726     vi->setPosition(170, 200);
727   else
728     vi->setPosition(160, 150);
729   vi->setOneLiner(tr("Connected, loading config"));
730   vi->draw();
731   boxstack->add(vi);
732   boxstack->update(vi);
733
734   VDR* vdr = VDR::getInstance();
735   char* config;
736
737   // See if we're supposed to do network logging
738   config = vdr->configLoad("Advanced", "Network logging");
739   if (config && !STRCASECMP(config, "On"))
740   {
741     logger->log("Command", Log::INFO, "Turning on network logging");
742     logger->setExternLogger(vdr);
743   }  
744   else
745   {
746           logger->unsetExternLogger();
747     logger->log("Command", Log::INFO, "Turned off network logging");
748   }
749   if (config) delete[] config;
750
751   // See if config says to override video format (PAL/NTSC)
752   config = vdr->configLoad("General", "Override Video Format");
753   if (config)
754   {
755     logger->log("Command", Log::DEBUG, "Override Video Format is present");
756
757     if (   (!strcmp(config, "PAL") && (video->getFormat() != Video::PAL))
758         || (!strcmp(config, "NTSC") && (video->getFormat() != Video::NTSC))
759         || (!strcmp(config, "PAL_M") && (video->getFormat() != Video::PAL_M))
760         || (!strcmp(config, "NTSC_J") && (video->getFormat() != Video::NTSC_J))
761         )
762     {
763       // Oh sheesh, need to switch format. Bye bye TV...
764
765       // Take everything down
766       boxstack->removeAll();
767       boxstack->remove(wallpaper);
768       Osd* osd = Osd::getInstance();
769 #ifndef __ANDROID__
770       osd->shutdown();
771 #endif
772       video->shutdown();
773
774       remote->shutdown(); // need on raspberry shut not do any harm, hopefully
775       remote->init(RemoteStartDev);
776
777       // Get video and osd back up with the new mode
778       if (!strcmp(config, "PAL"))
779       {
780         logger->log("Command", Log::DEBUG, "Switching to PAL");
781         video->init(Video::PAL);
782       }
783       else if (!strcmp(config, "NTSC"))
784       {
785         logger->log("Command", Log::DEBUG, "Switching to NTSC");
786         video->init(Video::NTSC);
787       } else if (!strcmp(config, "PAL_M"))
788       {
789         logger->log("Command", Log::DEBUG, "Switching to PAL_M");
790         video->init(Video::PAL_M);
791       } else if (!strcmp(config, "NTSC_J"))
792       {
793         logger->log("Command", Log::DEBUG, "Switching to NTSC_J");
794         video->init(Video::NTSC_J);
795       }
796 #ifndef __ANDROID__
797       //we do not init twice
798       osd->init((char*)("/dev/stbgfx"));
799 #endif
800
801       // Put the wallpaper back
802       doWallpaper();
803
804       // Re add the vinfo
805       vi = new VInfo();
806       vi->setSize(400, 200);
807       vi->createBuffer();
808       if (video->getFormat() == Video::PAL)
809         vi->setPosition(170, 200);
810       else
811         vi->setPosition(160, 150);
812
813       vi->setOneLiner(tr("Connected, loading config"));
814       vi->draw();
815       boxstack->add(vi);
816       boxstack->update(vi);
817     }
818     else
819     {
820       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
821     }
822   }
823   else
824   {
825     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
826   }
827
828   // Power off if first boot and config says so
829   if (firstBoot)
830   {
831     firstBoot = 0;
832
833     logger->log("Command", Log::DEBUG, "Load power after boot");
834
835     config = vdr->configLoad("General", "Power After Boot");
836
837     if (config)
838     {
839       if (!STRCASECMP(config, "On"))
840       {
841         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
842       }
843       else if (!STRCASECMP(config, "Off"))
844       {
845         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
846         doStandby();
847         delete[] config;
848         return; // quit here
849       }
850       else if (!STRCASECMP(config, "Last state"))
851       {
852         char* lastPowerState = vdr->configLoad("General", "Last Power State");
853         if (lastPowerState)
854         {
855           if (!STRCASECMP(lastPowerState, "On"))
856           {
857             logger->log("Command", Log::INFO, "Config says Last Power State = On");
858           }
859           else if (!STRCASECMP(lastPowerState, "Off"))
860           {
861             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
862             doStandby();
863             delete[] config;
864             return; // quit here
865           }
866           else
867           {
868             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
869           }
870         }
871         else
872         {
873           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
874         }
875       }
876       else
877       {
878         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
879       }
880       delete[] config;
881     }
882     else
883     {
884       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
885     }
886   }
887
888
889   // Go S-Video if config says so
890
891   config = vdr->configLoad("TV", "Connection");
892
893   if (config)
894   {
895     if (!STRCASECMP(config, "S-Video"))
896     {
897       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
898       video->setConnection(Video::SVIDEO);
899     } else  if (!STRCASECMP(config, "HDMI"))
900     {
901       logger->log("Command", Log::INFO, "Switching to HDMI as Connection=%s", config);
902       video->setConnection(Video::HDMI);
903     } else  if (!STRCASECMP(config, "HDMI3D"))
904     {
905       logger->log("Command", Log::INFO, "Switching to HDMI3D as Connection=%s", config);
906       video->setConnection(Video::HDMI3D);
907     }
908     else
909     {
910       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
911       video->setConnection(Video::COMPOSITERGB);
912     }
913     delete[] config;
914   }
915   else
916   {
917     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
918   }
919
920   // Set to shutdown VDR if config says
921   
922   config = vdr->configLoad("General", "VDR shutdown");
923   if (config)
924   {
925     if (!STRCASECMP(config, "On"))
926     {
927       logger->log("Command", Log::INFO, "Shutdown VDR when  shutting down vomp");
928       vdr->setVDRShutdown(true);
929     }
930     else if (!STRCASECMP(config, "Off"))
931     {
932       logger->log("Command", Log::INFO, "Shutdown only vomp");
933       vdr->setVDRShutdown(false);
934     }
935   }
936   else
937   {
938     logger->log("Command", Log::INFO, "Default shutdown only vomp");
939     vdr->setVDRShutdown(false); // Default
940   }
941           
942   // Set remote type
943
944   config = vdr->configLoad("General", "Remote type");
945
946   if (config)
947   {
948     if (!STRCASECMP(config, "New"))
949     {
950       logger->log("Command", Log::INFO, "Switching to New remote type");
951       remote->setRemoteType(Remote::NEWREMOTE);
952     }
953     else
954     {
955       logger->log("Command", Log::INFO, "Switching to Old remote type");
956       remote->setRemoteType(Remote::OLDREMOTE);
957     }
958     delete[] config;
959   }
960   else
961   {
962     logger->log("Command", Log::INFO, "Config General/Remote type not found");
963     remote->setRemoteType(Remote::OLDREMOTE);
964   }
965
966
967
968   // Get TV aspect ratio
969
970   config = vdr->configLoad("TV", "Aspect");
971   if (config)
972   {
973     if (!STRCASECMP(config, "16:9"))
974     {
975       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
976       video->setTVsize(Video::ASPECT16X9);
977     }
978     else
979     {
980       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
981       video->setTVsize(Video::ASPECT4X3);
982     }
983     delete[] config;
984   }
985   else
986   {
987     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
988     video->setTVsize(Video::ASPECT4X3);
989   }
990
991   config = vdr->configLoad("TV", "Widemode");
992   if (config)
993   {
994     if (!STRCASECMP(config, "Letterbox"))
995     {
996       logger->log("Command", Log::INFO, "Setting letterbox mode");
997       video->setMode(Video::LETTERBOX);
998     }
999     else
1000     {
1001       logger->log("Command", Log::INFO, "Setting chop-sides mode");
1002       video->setMode(Video::NORMAL);
1003     }
1004     delete[] config;
1005   }
1006   else
1007   {
1008 #ifdef __ANDROID__
1009          logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");
1010          video->setMode(Video::LETTERBOX);
1011 #else
1012     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
1013     video->setMode(Video::NORMAL);
1014 #endif
1015   }
1016
1017   config = vdr->configLoad("Advanced", "TCP receive window");
1018   if (config)
1019   {
1020     size_t newTCPsize = atoi(config);
1021     delete[] config;
1022
1023     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
1024     vdr->setReceiveWindow(newTCPsize);
1025   }
1026   else
1027   {
1028     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
1029     if (DEFAULT_TCP_WINDOWSIZE) vdr->setReceiveWindow(2048); // Default
1030   }
1031
1032   config = vdr->configLoad("Advanced", "Font Name");
1033   if (config)
1034   {
1035         Osd::getInstance()->setFont(config);
1036     logger->log("Command", Log::INFO, "Setting Font to %s", config);
1037     delete[] config;
1038
1039   }
1040
1041
1042   // Set recording list type
1043
1044   advmenues=false;
1045 #ifdef    ADVANCED_MENUES
1046   config = vdr->configLoad("Advanced", "Menu type");
1047
1048   if (config)
1049   {
1050           if (!STRCASECMP(config, "Advanced"))
1051           {
1052                   logger->log("Command", Log::INFO, "Switching to Advanced menu");
1053                   advmenues=true;
1054
1055           }
1056           else
1057           {
1058                   logger->log("Command", Log::INFO, "Switching to Classic menu");
1059                   advmenues=false;
1060           }
1061           delete[] config;
1062   }
1063   else
1064   {
1065           logger->log("Command", Log::INFO, "Config General/menu type not found");
1066           advmenues=true;
1067   }
1068 #endif
1069
1070   config = vdr->configLoad("Advanced", "Disable WOL");
1071   if (config)
1072   {
1073     if (!STRCASECMP(config, "Yes"))
1074     {
1075       logger->log("Command", Log::INFO, "Config says disable WOL");
1076       Wol::getInstance()->setEnabled(false);
1077     }
1078     else
1079     {
1080       logger->log("Command", Log::INFO, "Config says enable WOL");
1081       Wol::getInstance()->setEnabled(true);
1082     }
1083
1084     delete[] config;
1085   }
1086   else
1087   {
1088     logger->log("Command", Log::INFO, "By default, enable WOL");
1089     Wol::getInstance()->setEnabled(true);
1090   }
1091   /* device dependend config */
1092   audio->loadOptionsfromServer(vdr);
1093   video->loadOptionsfromServer(vdr);
1094   remote->loadOptionsfromServer(vdr);
1095
1096   video->executePendingModeChanges();
1097   // config done
1098
1099   // Save power state = on
1100
1101   vdr->configSave("General", "Last Power State", "On");
1102
1103   // Make sure connection didn't die
1104   if (!vdr->isConnected())
1105   {
1106     Command::getInstance()->connectionLost();
1107   }
1108   else
1109   {
1110     boxstack->remove(vi);
1111
1112     VWelcome* vw = new VWelcome();
1113     vw->draw();
1114     boxstack->add(vw);
1115     boxstack->update(vw);
1116
1117     // Enter pre-keys here
1118 //    handleCommand(Remote::OK);
1119 //    handleCommand(Remote::THREE);
1120 //    handleCommand(Remote::SIX);
1121 //    handleCommand(Remote::OK);
1122 //    handleCommand(Remote::UP);
1123 //    handleCommand(Remote::PLAY);
1124 //    handleCommand(Remote::DOWN);
1125 //    handleCommand(Remote::DOWN);
1126 //    handleCommand(Remote::DOWN);
1127  //   handleCommand(Remote::OK);
1128 //    handleCommand(Remote::RED);
1129   }
1130 }