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