]> git.vomp.tv Git - vompclient.git/blob - command.cc
Switch trunk code to new boxes
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include <linux/errno.h>
22
23 #include "command.h"
24
25 #ifdef WIN32
26 #include "remotewin.h"
27 #endif
28
29 #include "led.h"
30 #include "video.h"
31 #include "vdr.h"
32 #include "vvolume.h"
33 #include "vserverselect.h"
34 #include "vwelcome.h"
35 #include "vmute.h"
36 #include "colour.h"
37 #include "osd.h"
38 #include "i18n.h"
39 #include "timerreceiver.h"
40 #include "timers.h"
41 #include "wol.h"
42 #include "vvideolive.h"
43 #include "vconnect.h"
44 #include "message.h"
45 #include "remote.h"
46 #include "vinfo.h"
47 #include "boxx.h"
48 #include "boxstack.h"
49 #include "log.h"
50
51
52 Command* Command::instance = NULL;
53
54 Command::Command()
55 {
56   if (instance) return;
57   instance = this;
58   initted = 0;
59   isStandby = 0;
60   firstBoot = 1;
61   connLost = NULL;
62 }
63
64 Command::~Command()
65 {
66   instance = NULL;
67 }
68
69 Command* Command::getInstance()
70 {
71   return instance;
72 }
73
74 int Command::init()
75 {
76   if (initted) return 0;
77   initted = 1;
78
79   logger = Log::getInstance();
80   boxstack = BoxStack::getInstance();
81   remote = Remote::getInstance();
82   
83   if (!logger || !boxstack || !remote)
84   {
85     initted = 0;
86     return 0;
87   }
88 #ifndef WIN32
89   pthread_mutex_init(&masterLock, NULL);
90 #else
91   masterLock=CreateMutex(NULL,FALSE,NULL);
92 #endif
93
94   return 1;
95 }
96
97 int Command::shutdown()
98 {
99   if (!initted) return 0;
100   initted = 0;
101   return 1;
102 }
103
104 void Command::stop()
105 {
106 //  VDR::getInstance()->cancelFindingServer();
107   udp.shutdown();
108   irun = 0;
109 }
110
111 void Command::doWallpaper()
112 {
113   Video* video = Video::getInstance();
114
115   // Blue background
116   Boxx* bbg = new Boxx();
117   bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
118   bbg->createBuffer();
119   bbg->fillColour(Colour::VIDEOBLUE);
120   boxstack->add(bbg);
121   boxstack->update(bbg);
122   boxstack->remove(bbg);
123
124   // Wallpaper
125   WJpeg* wallpaperj = new WJpeg();
126   wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
127   wallpaperj->createBuffer();
128
129   if (video->getFormat() == Video::PAL)
130   {
131     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
132     wallpaperj->init("/wallpaperPAL.jpg");
133   }
134   else
135   {
136     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
137     wallpaperj->init("/wallpaperNTSC.jpg");
138   }
139   wallpaperj->draw();
140
141   boxstack->add(wallpaperj);
142   boxstack->update(wallpaperj);
143
144   wallpaper = wallpaperj;
145 }
146
147 void Command::run()
148 {
149   if (!initted) return;
150   irun = 1;
151 #ifndef WIN32
152   mainPid = getpid();
153 #endif
154
155   // just in case
156   Video::getInstance()->signalOn();
157   Led::getInstance()->on();
158
159   doWallpaper();
160
161   // End of startup. Lock the mutex and put the first view up
162 //  logger->log("Command", Log::DEBUG, "WANT LOCK");
163 #ifndef WIN32
164   pthread_mutex_lock(&masterLock);
165 #else
166   WaitForSingleObject(masterLock, INFINITE );
167 #endif
168   //logger->log("Command", Log::DEBUG, "LOCKED");
169
170   VConnect* vconnect = new VConnect();
171   boxstack->add(vconnect);
172   vconnect->run();
173
174   // Start method 2 of getting commands in...
175   udp.run(this);
176
177   UCHAR button = 0;
178   while(irun)
179   {
180     // unlock and wait
181     //logger->log("Command", Log::DEBUG, "UNLOCK");
182 #ifndef WIN32
183     pthread_mutex_unlock(&masterLock);
184 #else
185     ReleaseMutex(masterLock);
186 #endif
187     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
188     // something happened, lock and process
189
190     //  logger->log("Command", Log::DEBUG, "WANT LOCK");
191 #ifndef WIN32
192     pthread_mutex_lock(&masterLock);
193 #else
194     WaitForSingleObject(masterLock, INFINITE );
195 #endif
196     // logger->log("Command", Log::DEBUG, "LOCK");
197
198     if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
199
200     if (button != Remote::NA_SIGNAL) handleCommand(button);
201     processMessageQueue();
202   }
203
204   //logger->log("Command", Log::DEBUG, "UNLOCK");
205 #ifndef WIN32
206   pthread_mutex_unlock(&masterLock);
207 #else
208   ReleaseMutex(masterLock);
209 #endif
210 }
211
212 void Command::postMessage(Message* m)
213 {
214   // This is locked here in case the main loop is not waiting for an event, but is processing one
215   // it could be killed but then not react to it because the signal wouldn't cause
216   // remote->getButtonPress to break
217   // locking the mutex ensures that the master thread is waiting on getButtonPress
218
219
220   //logger->log("Command", Log::DEBUG, "WANT LOCK");
221 #ifndef WIN32
222   pthread_mutex_lock(&masterLock);
223 #else
224   WaitForSingleObject(masterLock, INFINITE );
225 #endif
226   //logger->log("Command", Log::DEBUG, "LOCK");
227   MessageQueue::postMessage(m);
228
229 #ifndef WIN32
230   kill(mainPid, SIGURG);
231   pthread_mutex_unlock(&masterLock);
232 #else
233   ((RemoteWin*)Remote::getInstance())->Signal();
234   ReleaseMutex(masterLock);
235 #endif
236   //logger->log("Command", Log::DEBUG, "UNLOCK");
237 }
238
239 void Command::postMessageNoLock(Message* m)
240 {
241   // As above but use this one if this message is being posted because of a button press
242   // the mutex is already locked, locking around postMessage is not needed as the
243   // queue is guaranteed to be run when the button has been processed
244   MessageQueue::postMessage(m);
245 }
246
247 bool Command::postMessageIfNotBusy(Message* m)
248 {
249   // Used for Windows mouse events
250
251   //logger->log("Command", Log::DEBUG, "TRY LOCK");
252 #ifndef WIN32
253   if (pthread_mutex_trylock(&masterLock) != EBUSY)
254   {
255     //logger->log("Command", Log::DEBUG, "LOCK");
256     MessageQueue::postMessage(m);
257     kill(mainPid, SIGURG);
258     pthread_mutex_unlock(&masterLock);
259     //logger->log("Command", Log::DEBUG, "UNLOCK");
260     return true;
261   }
262   else
263   {
264     return false;
265   }
266 #else
267   switch (WaitForSingleObject(masterLock, 0 ))
268   { //FIXME this is not "if not busy" check
269     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
270     // case WAIT_ABANDONED:
271     MessageQueue::postMessage(m);
272     ((RemoteWin*)Remote::getInstance())->Signal();
273     ReleaseMutex(masterLock);
274     return true;
275
276     case WAIT_ABANDONED: return false;
277     case WAIT_TIMEOUT: return false;
278   }
279     return false;
280 #endif
281 }
282
283 void Command::postMessageFromOuterSpace(Message* m)
284 {
285   /*
286   Yet another way of getting messages into Command. This one is for events that
287   are not standard button presses (or UDP generated buttons). It is also not for
288   events that are generated as a result of other events (events that can safely
289   call postMessageNoLock and be guaranteed that the message will be processed
290   because it is known that the queue is currently being processed).
291   This is for events that come from outer space and can occur when the master
292   mutex is locked or not, they need to be queued and executed but it doesn't
293   matter when.
294   Actually so far it is for events caused by the video stream - aspect ratio
295   changes. These can occur when the master mutex is locked and so postMessage
296   doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
297   locked at the time then the message could be sat around a while before
298   being noticed.
299   The whole message system was at first supposed to prevent the problem of
300   calling a function on an object that had just been deleted, by ordering
301   messages such that all calls are done before object deletion. However,
302   because of the new centralised messaging system and the fact that BoxStack
303   locates the destination object before calling it, the messaging system now
304   allows the kind of sloppy calls it was supposed to stop. Weird huh. This
305   is mentioned here because the video stream might generate an event just as
306   the user hits stop. The mutex is locked, and by the time the message
307   is examined the vvideorec/live has been deleted. This doesn't matter because
308   boxstack will drop the message if it can't find the matching object to
309   deliver it to.
310   Finally, all this is fine and dandy, except that I'm not 100% sure that
311   this sloppy postMessage and hope a queued signal will force it to be processed
312   thingy will actually work. Hmmm.
313   Lastly <g>, I will consider making the naming system a little more sane
314   if this works.
315   */
316
317   logger->log("Command", Log::DEBUG, "PMFOS called");
318   MessageQueue::postMessage(m);
319
320 #ifndef WIN32
321   kill(mainPid, SIGURG);
322 #else
323   ((RemoteWin*)Remote::getInstance())->Signal();
324 #endif
325 }
326
327 void Command::processMessage(Message* m)
328 {
329     // FIXME - a slight modification - how if messagereceivers were to register
330     // themselves as receivers to avoid the calling-a-deleted-object problem
331     // then only deliver/register/unregister would have to be protected
332
333   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
334
335
336   if (m->to == this)
337   {
338     switch(m->message)
339     {
340       case Message::STANDBY:
341       {
342         doStandby();
343         break;
344       }
345
346
347       // << FIXME OBSELETE
348       case Message::STOP_PLAYBACK:
349       {
350         handleCommand(Remote::STOP); // an odd way of doing it, but so simple
351         break;
352       }
353       case Message::STREAM_END:
354       {
355         VVideoLive::getInstance()->streamEnd();
356         break;
357       }
358
359       // Also connection_lost comes from player - anywhere else?
360       // FIXME OBSELETE >>
361
362
363       case Message::VDR_CONNECTED:
364       {
365         doJustConnected((VConnect*)m->from);
366         break;
367       }
368       case Message::SCREENSHOT:
369       {
370         Osd::getInstance()->screenShot("/out.jpg");
371         break;
372       }
373       case Message::CONNECTION_LOST:
374       {
375         doFromTheTop(true);
376         break;
377       }
378       case Message::UDP_BUTTON:
379       {
380         handleCommand(m->parameter);
381         break;
382       }
383       case Message::CHANGE_LANGUAGE:
384       {
385         boxstack->removeAll();
386         boxstack->update(wallpaper);
387         I18n::initialize();
388         VWelcome* vw = new VWelcome();
389         vw->draw();
390         boxstack->add(vw);
391         boxstack->update(vw);
392         break;
393       }
394       case Message::LAST_VIEW_CLOSE:
395       {
396 //        not currently used
397 //        VWelcome* vw = new VWelcome();
398 //        vw->draw();
399 //        boxstack->add(vw);
400 //        boxstack->update(vw);
401
402         break;
403       }
404     }
405   }
406   else
407   {
408     logger->log("Command", Log::DEBUG, "Sending message to boxstack");
409     boxstack->processMessage(m);
410   }
411 }
412
413 void Command::handleCommand(int button)
414 {
415   if (isStandby && (button != Remote::POWER)) return;
416   if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
417
418   // command was not handled
419
420   switch(button)
421   {
422     case Remote::DF_LEFT:
423     case Remote::DF_RIGHT:
424     case Remote::VOLUMEUP:
425     case Remote::VOLUMEDOWN:
426     {
427       VVolume* v = new VVolume();
428       boxstack->add(v);
429       v->handleCommand(button); // this will draw+show
430       return;
431     }
432     case Remote::MUTE:
433     {
434       VMute* v = new VMute();
435       v->draw();
436       boxstack->add(v);
437       boxstack->update(v);
438       return;
439     }
440     case Remote::POWER:
441     {
442       doStandby();
443       return;
444     }
445     case Remote::OK:
446     {
447       if (!connLost) return; // if connLost, handle Remote::OK
448       doFromTheTop(false);
449       return;
450     }
451   }
452 }
453
454 void Command::sig1()
455 {
456 #ifdef DEV
457   Message* m = new Message(); // break into master mutex
458   m->message = Message::SCREENSHOT;
459   m->to = this;
460   postMessage(m);
461 #endif
462 }
463
464 void Command::doStandby()
465 {
466   if (isStandby)
467   {
468     Video::getInstance()->signalOn();
469     Led::getInstance()->on();
470     isStandby = 0;
471
472
473     VConnect* vconnect = new VConnect();
474     boxstack->add(vconnect);
475     vconnect->run();
476   }
477   else
478   {
479     boxstack->removeAll();
480     Video::getInstance()->signalOff();
481     boxstack->update(wallpaper);
482
483     VDR::getInstance()->configSave("General", "Last Power State", "Off");
484     VDR::getInstance()->disconnect();
485     Led::getInstance()->off();
486     isStandby = 1;
487 #ifdef WIN32
488     stop(); //different behavoiur on windows, we exit
489 #endif
490   }
491 }
492
493 void Command::doFromTheTop(bool which)
494 {
495   if (which)
496   {
497     connLost = new VInfo();
498     connLost->setSize(360, 200);
499     connLost->createBuffer();
500     if (Video::getInstance()->getFormat() == Video::PAL)
501       connLost->setPosition(190, 170);
502     else
503       connLost->setPosition(180, 120);
504     connLost->setOneLiner(tr("Connection lost"));
505     connLost->setDropThrough();
506     connLost->setBorderOn(1);
507     connLost->setTitleBarColour(Colour::DANGER);
508     connLost->okButton();
509     connLost->draw();
510     boxstack->add(connLost);
511     boxstack->update(connLost);
512     remote->clearBuffer();
513   }
514   else
515   {
516     VDR::getInstance()->disconnect();
517     boxstack->removeAll();
518     boxstack->update(wallpaper);
519     connLost = NULL;
520     VConnect* vconnect = new VConnect();
521     boxstack->add(vconnect);
522     vconnect->run();
523   }
524 }
525
526 void Command::doReboot()
527 {
528   VDR::getInstance()->disconnect();
529   // just kill it...
530   logger->log("Command", Log::NOTICE, "Reboot");
531 #ifndef WIN32
532   reboot(LINUX_REBOOT_CMD_RESTART);
533 #endif //Would we support this on windows?
534 }
535
536 void Command::connectionLost()
537 {
538   Message* m = new Message(); // break into master mutex
539   m->message = Message::CONNECTION_LOST;
540   m->to = this;
541   postMessageNoLock(m);
542 }
543
544 void Command::doJustConnected(VConnect* vconnect)
545 {
546   I18n::initialize();
547   Video* video = Video::getInstance();
548   boxstack->remove(vconnect);
549
550   VInfo* vi = new VInfo();
551   vi->setSize(400, 200);
552   vi->createBuffer();
553   if (video->getFormat() == Video::PAL)
554     vi->setPosition(170, 200);
555   else
556     vi->setPosition(160, 150);
557   vi->setOneLiner(tr("Connected, loading config"));
558   vi->draw();
559   boxstack->add(vi);
560   boxstack->update(vi);
561
562   VDR* vdr = VDR::getInstance();
563   char* config;
564
565   // See if config says to override video format (PAL/NTSC)
566   config = vdr->configLoad("General", "Override Video Format");
567   if (config)
568   {
569     logger->log("Command", Log::DEBUG, "Override Video Format is present");
570
571     if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
572         || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )
573     {
574       // Oh sheesh, need to switch format. Bye bye TV...
575
576       // Take everything down
577       boxstack->removeAll();
578       boxstack->remove(wallpaper);
579       Osd* osd = Osd::getInstance();
580       osd->shutdown();
581       video->shutdown();
582
583       // Get video and osd back up with the new mode
584       if (!strcmp(config, "PAL"))
585       {
586         logger->log("Command", Log::DEBUG, "Switching to PAL");
587         video->init(Video::PAL);
588       }
589       else if (!strcmp(config, "NTSC"))
590       {
591         logger->log("Command", Log::DEBUG, "Switching to NTSC");
592         video->init(Video::NTSC);
593       }
594       osd->init((char*)("/dev/stbgfx"));
595
596       // Put the wallpaper back
597       doWallpaper();
598
599       // Re add the vinfo
600       vi = new VInfo();
601       vi->setSize(400, 200);
602       vi->createBuffer();
603       if (video->getFormat() == Video::PAL)
604         vi->setPosition(170, 200);
605       else
606         vi->setPosition(160, 150);
607
608       vi->setOneLiner(tr("Connected, loading config"));
609       vi->draw();
610       boxstack->add(vi);
611       boxstack->update(vi);
612     }
613     else
614     {
615       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
616     }
617   }
618   else
619   {
620     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
621   }
622
623   // Power off if first boot and config says so
624   if (firstBoot)
625   {
626     firstBoot = 0;
627
628     logger->log("Command", Log::DEBUG, "Load power after boot");
629
630     config = vdr->configLoad("General", "Power After Boot");
631
632     if (config)
633     {
634       if (!STRCASECMP(config, "On"))
635       {
636         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
637       }
638       else if (!STRCASECMP(config, "Off"))
639       {
640         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
641         doStandby();
642         delete[] config;
643         return; // quit here
644       }
645       else if (!STRCASECMP(config, "Last state"))
646       {
647         char* lastPowerState = vdr->configLoad("General", "Last Power State");
648         if (lastPowerState)
649         {
650           if (!STRCASECMP(lastPowerState, "On"))
651           {
652             logger->log("Command", Log::INFO, "Config says Last Power State = On");
653           }
654           else if (!STRCASECMP(lastPowerState, "Off"))
655           {
656             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
657             doStandby();
658             delete[] config;
659             return; // quit here
660           }
661           else
662           {
663             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
664           }
665         }
666         else
667         {
668           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
669         }
670       }
671       else
672       {
673         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
674       }
675       delete[] config;
676     }
677     else
678     {
679       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
680     }
681   }
682
683
684   // Go S-Video if config says so
685
686   config = vdr->configLoad("TV", "Connection");
687
688   if (config)
689   {
690     if (!STRCASECMP(config, "S-Video"))
691     {
692       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
693       video->setConnection(Video::SVIDEO);
694     }
695     else
696     {
697       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
698       video->setConnection(Video::COMPOSITERGB);
699     }
700     delete[] config;
701   }
702   else
703   {
704     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
705   }
706
707   // Set remote type
708
709   config = vdr->configLoad("General", "Remote type");
710
711   if (config)
712   {
713     if (!STRCASECMP(config, "New"))
714     {
715       logger->log("Command", Log::INFO, "Switching to New remote type");
716       remote->setRemoteType(Remote::NEWREMOTE);
717     }
718     else
719     {
720       logger->log("Command", Log::INFO, "Switching to Old remote type");
721       remote->setRemoteType(Remote::OLDREMOTE);
722     }
723     delete[] config;
724   }
725   else
726   {
727     logger->log("Command", Log::INFO, "Config General/Remote type not found");
728     remote->setRemoteType(Remote::OLDREMOTE);
729   }
730
731    // Set remote keys
732
733   config = vdr->configLoad("General", "Remote keys");
734
735   if (config)
736   {
737     logger->log("Command", Log::INFO, "Config General/Remote keys load");
738     remote->LoadKeysConfig(config);
739     delete[] config;
740   }
741   else
742   {
743     logger->log("Command", Log::INFO, "Config General/Remote keys not found");
744     remote->InitHWCListwithDefaults();
745   }
746
747   // Get TV aspect ratio
748
749   config = vdr->configLoad("TV", "Aspect");
750   if (config)
751   {
752     if (!STRCASECMP(config, "16:9"))
753     {
754       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
755       video->setTVsize(Video::ASPECT16X9);
756     }
757     else
758     {
759       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
760       video->setTVsize(Video::ASPECT4X3);
761     }
762     delete[] config;
763   }
764   else
765   {
766     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
767     video->setTVsize(Video::ASPECT4X3);
768   }
769
770   config = vdr->configLoad("TV", "Widemode");
771   if (config)
772   {
773     if (!STRCASECMP(config, "Letterbox"))
774     {
775       logger->log("Command", Log::INFO, "Setting letterbox mode");
776       video->setMode(Video::LETTERBOX);
777     }
778     else
779     {
780       logger->log("Command", Log::INFO, "Setting chop-sides mode");
781       video->setMode(Video::NORMAL);
782     }
783     delete[] config;
784   }
785   else
786   {
787     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
788     video->setMode(Video::NORMAL);
789   }
790
791   config = vdr->configLoad("Advanced", "TCP receive window");
792   if (config)
793   {
794     size_t newTCPsize = atoi(config);
795     delete[] config;
796
797     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
798     vdr->setReceiveWindow(newTCPsize);
799   }
800   else
801   {
802     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
803     vdr->setReceiveWindow(2048); // Default
804   }
805
806   config = vdr->configLoad("Advanced", "Disable WOL");
807   if (config)
808   {
809     if (!STRCASECMP(config, "Yes"))
810     {
811       logger->log("Command", Log::INFO, "Config says disable WOL");
812       Wol::getInstance()->setEnabled(false);
813     }
814     else
815     {
816       logger->log("Command", Log::INFO, "Config says enable WOL");
817       Wol::getInstance()->setEnabled(true);
818     }
819
820     delete[] config;
821   }
822   else
823   {
824     logger->log("Command", Log::INFO, "By default, enable WOL");
825     Wol::getInstance()->setEnabled(true);
826   }
827
828   // config done
829
830   // Save power state = on
831
832   vdr->configSave("General", "Last Power State", "On");
833
834   // Make sure connection didn't die
835   if (!vdr->isConnected())
836   {
837     Command::getInstance()->connectionLost();
838   }
839   else
840   {
841     boxstack->remove(vi);
842
843     VWelcome* vw = new VWelcome();
844     vw->draw();
845     boxstack->add(vw);
846     boxstack->update(vw);
847
848     // Enter pre-keys here
849 //    handleCommand(Remote::SIX);
850 //    handleCommand(Remote::UP);
851 //    handleCommand(Remote::PLAY);
852 //    handleCommand(Remote::DOWN);
853 //    handleCommand(Remote::DOWN);
854 //    handleCommand(Remote::DOWN);
855 //    handleCommand(Remote::OK);
856 //    handleCommand(Remote::OK);
857 //    handleCommand(Remote::RED);
858   }
859 }