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