2 Copyright 2004-2005 Chris Tallon
\r
4 This file is part of VOMP.
\r
6 VOMP is free software; you can redistribute it and/or modify
\r
7 it under the terms of the GNU General Public License as published by
\r
8 the Free Software Foundation; either version 2 of the License, or
\r
9 (at your option) any later version.
\r
11 VOMP is distributed in the hope that it will be useful,
\r
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
14 GNU General Public License for more details.
\r
16 You should have received a copy of the GNU General Public License
\r
17 along with VOMP; if not, write to the Free Software
\r
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
22 #include <linux/errno.h>
\r
25 #include "command.h"
\r
28 #include "remotewin.h"
\r
32 #include "remoteandroid.h"
\r
39 #include "vvolume.h"
\r
40 #include "vserverselect.h"
\r
41 #include "vwelcome.h"
\r
46 #include "timerreceiver.h"
\r
49 #include "vconnect.h"
\r
50 #include "message.h"
\r
54 #include "boxstack.h"
\r
56 #include "vsleeptimer.h"
\r
59 Command* Command::instance = NULL;
\r
63 if (instance) return;
\r
78 Command* Command::getInstance()
\r
83 int Command::init(bool tcrashed, char* tServer)
\r
85 if (initted) return 0;
\r
90 logger = Log::getInstance();
\r
91 boxstack = BoxStack::getInstance();
\r
92 remote = Remote::getInstance();
\r
94 remote->InitHWCListwithDefaults();
\r
96 if (!logger || !boxstack || !remote)
\r
102 pthread_mutex_init(&masterLock, NULL);
\r
104 masterLock=CreateMutex(NULL,FALSE,NULL);
\r
110 int Command::shutdown()
\r
112 if (!initted) return 0;
\r
117 void Command::stop()
\r
119 // VDR::getInstance()->cancelFindingServer();
\r
120 logger->log("Command", Log::NOTICE, "Command stop1...");
\r
123 logger->log("Command", Log::NOTICE, "Command stop2...");
\r
127 void Command::doWallpaper()
\r
129 Video* video = Video::getInstance();
\r
132 Boxx* bbg = new Boxx();
\r
133 bbg->setSize(video->getScreenWidth(), video->getScreenHeight());
\r
134 bbg->createBuffer();
\r
135 bbg->fillColour(Colour::VIDEOBLUE);
\r
136 boxstack->add(bbg);
\r
137 boxstack->update(bbg);
\r
138 boxstack->remove(bbg);
\r
141 WJpeg* wallpaperj = new WJpegTYPE();
\r
142 wallpaperj->setSize(video->getScreenWidth(), video->getScreenHeight());
\r
143 wallpaperj->createBuffer();
\r
145 if (video->getFormat() == Video::PAL)
\r
147 logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
\r
148 #ifndef _MIPS_ARCH
\r
149 wallpaperj->init("/wallpaperPAL.jpg");
\r
151 wallpaperj->init("wallpaperPAL.jpg");
\r
156 logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
\r
157 wallpaperj->init("/wallpaperNTSC.jpg");
\r
159 wallpaperj->draw();
\r
161 boxstack->add(wallpaperj);
\r
162 boxstack->update(wallpaperj);
\r
164 wallpaper = wallpaperj;
\r
167 void Command::run()
\r
169 if (!initted) return;
\r
172 mainPid = getpid();
\r
176 Video::getInstance()->signalOn();
\r
177 Led::getInstance()->on();
\r
181 // End of startup. Lock the mutex and put the first view up
\r
182 // logger->log("Command", Log::DEBUG, "WANT LOCK");
\r
184 pthread_mutex_lock(&masterLock);
\r
186 WaitForSingleObject(masterLock, INFINITE );
\r
188 //logger->log("Command", Log::DEBUG, "LOCKED");
\r
196 VConnect* vconnect = new VConnect(server);
\r
197 boxstack->add(vconnect);
\r
201 // Start method 2 of getting commands in...
\r
208 //logger->log("Command", Log::DEBUG, "UNLOCK");
\r
210 pthread_mutex_unlock(&masterLock);
\r
212 ReleaseMutex(masterLock);
\r
215 button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit
\r
216 // something happened, lock and process
\r
218 // logger->log("Command", Log::DEBUG, "WANT LOCK");
\r
220 pthread_mutex_lock(&masterLock);
\r
222 WaitForSingleObject(masterLock, INFINITE );
\r
224 // logger->log("Command", Log::DEBUG, "LOCK");
\r
226 if ((button == Remote::NA_NONE) /*|| (button == Remote::NA_UNKNOWN)*/) continue;
\r
228 if (button != Remote::NA_SIGNAL) handleCommand(button);
\r
229 processMessageQueue();
\r
233 //logger->log("Command", Log::DEBUG, "UNLOCK");
\r
235 pthread_mutex_unlock(&masterLock);
\r
237 ReleaseMutex(masterLock);
\r
243 void Command::postMessage(Message* m)
\r
245 // This is locked here in case the main loop is not waiting for an event, but is processing one
\r
246 // it could be killed but then not react to it because the signal wouldn't cause
\r
247 // remote->getButtonPress to break
\r
248 // locking the mutex ensures that the master thread is waiting on getButtonPress
\r
251 //logger->log("Command", Log::DEBUG, "WANT LOCK");
\r
253 pthread_mutex_lock(&masterLock);
\r
255 WaitForSingleObject(masterLock, INFINITE );
\r
257 //logger->log("Command", Log::DEBUG, "LOCK");
\r
258 MessageQueue::postMessage(m);
\r
261 #ifndef __ANDROID__
\r
262 kill(mainPid, SIGURG);
\r
264 ((RemoteAndroid*)Remote::getInstance())->Signal();
\r
266 pthread_mutex_unlock(&masterLock);
\r
268 ((RemoteWin*)Remote::getInstance())->Signal();
\r
269 ReleaseMutex(masterLock);
\r
271 //logger->log("Command", Log::DEBUG, "UNLOCK");
\r
274 void Command::postMessageNoLock(Message* m)
\r
276 // As above but use this one if this message is being posted because of a button press
\r
277 // the mutex is already locked, locking around postMessage is not needed as the
\r
278 // queue is guaranteed to be run when the button has been processed
\r
279 MessageQueue::postMessage(m);
\r
282 bool Command::postMessageIfNotBusy(Message* m)
\r
284 // Used for Windows mouse events
\r
286 //logger->log("Command", Log::DEBUG, "TRY LOCK");
\r
288 if (pthread_mutex_trylock(&masterLock) != EBUSY)
\r
290 //logger->log("Command", Log::DEBUG, "LOCK");
\r
291 MessageQueue::postMessage(m);
\r
292 #ifndef __ANDROID__
\r
293 kill(mainPid, SIGURG);
\r
295 ((RemoteAndroid*)Remote::getInstance())->Signal();
\r
297 pthread_mutex_unlock(&masterLock);
\r
298 //logger->log("Command", Log::DEBUG, "UNLOCK");
\r
306 switch (WaitForSingleObject(masterLock, 0 ))
\r
307 { //FIXME this is not "if not busy" check
\r
308 case WAIT_OBJECT_0: //but with proper argument 0 this did not work
\r
309 // case WAIT_ABANDONED:
\r
310 MessageQueue::postMessage(m);
\r
311 ((RemoteWin*)Remote::getInstance())->Signal();
\r
312 ReleaseMutex(masterLock);
\r
315 case WAIT_ABANDONED: return false;
\r
316 case WAIT_TIMEOUT: return false;
\r
322 void Command::postMessageFromOuterSpace(Message* m)
\r
325 Yet another way of getting messages into Command. This one is for events that
\r
326 are not standard button presses (or UDP generated buttons). It is also not for
\r
327 events that are generated as a result of other events (events that can safely
\r
328 call postMessageNoLock and be guaranteed that the message will be processed
\r
329 because it is known that the queue is currently being processed).
\r
330 This is for events that come from outer space and can occur when the master
\r
331 mutex is locked or not, they need to be queued and executed but it doesn't
\r
333 Actually so far it is for events caused by the video stream - aspect ratio
\r
334 changes. These can occur when the master mutex is locked and so postMessage
\r
335 doesn't work. postMessageNoLock doesn't work because if the mutex *isn't*
\r
336 locked at the time then the message could be sat around a while before
\r
338 The whole message system was at first supposed to prevent the problem of
\r
339 calling a function on an object that had just been deleted, by ordering
\r
340 messages such that all calls are done before object deletion. However,
\r
341 because of the new centralised messaging system and the fact that BoxStack
\r
342 locates the destination object before calling it, the messaging system now
\r
343 allows the kind of sloppy calls it was supposed to stop. Weird huh. This
\r
344 is mentioned here because the video stream might generate an event just as
\r
345 the user hits stop. The mutex is locked, and by the time the message
\r
346 is examined the vvideorec/live has been deleted. This doesn't matter because
\r
347 boxstack will drop the message if it can't find the matching object to
\r
349 Finally, all this is fine and dandy, except that I'm not 100% sure that
\r
350 this sloppy postMessage and hope a queued signal will force it to be processed
\r
351 thingy will actually work. Hmmm.
\r
352 Lastly <g>, I will consider making the naming system a little more sane
\r
356 logger->log("Command", Log::DEBUG, "PMFOS called");
\r
357 MessageQueue::postMessage(m);
\r
360 #ifndef __ANDROID__
\r
361 kill(mainPid, SIGURG);
\r
363 ((RemoteAndroid*)Remote::getInstance())->Signal();
\r
366 ((RemoteWin*)Remote::getInstance())->Signal();
\r
370 void Command::processMessage(Message* m)
\r
372 // FIXME - a slight modification - how if messagereceivers were to register
\r
373 // themselves as receivers to avoid the calling-a-deleted-object problem
\r
374 // then only deliver/register/unregister would have to be protected
\r
376 logger->log("Command", Log::DEBUG, "processing message %i", m->message);
\r
383 // << FIXME OBSELETE
\r
384 case Message::STOP_PLAYBACK:
\r
386 handleCommand(Remote::STOP); // an odd way of doing it, but so simple
\r
389 // Also connection_lost comes from player - anywhere else?
\r
390 // FIXME OBSELETE >>
\r
393 case Message::VDR_CONNECTED:
\r
395 doJustConnected((VConnect*)m->from);
\r
398 case Message::SCREENSHOT:
\r
400 Osd::getInstance()->screenShot("/out.jpg");
\r
403 case Message::CONNECTION_LOST:
\r
405 doFromTheTop(true);
\r
408 case Message::UDP_BUTTON:
\r
410 handleCommand(m->parameter);
\r
413 case Message::CHANGE_LANGUAGE:
\r
415 boxstack->removeAll();
\r
416 boxstack->update(wallpaper);
\r
417 I18n::initialize();
\r
418 if (!VDR::getInstance()->isConnected()) { connectionLost(); break; }
\r
419 VWelcome* vw = new VWelcome();
\r
422 boxstack->update(vw);
\r
425 case Message::LAST_VIEW_CLOSE:
\r
427 // Shouldn't be done like this. Some generic message pass back from vinfo perhaps
\r
431 doFromTheTop(false);
\r
434 // VWelcome* vw = new VWelcome();
\r
436 // boxstack->add(vw);
\r
437 // boxstack->update(vw);
\r
447 Instead of sending through the boxstack, implement a more generic MessageReceiver interface
\r
448 and have potential receivers register with something
\r
449 When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
\r
450 This could all be done using the existing big command mutex to keep it simple
\r
453 logger->log("Command", Log::DEBUG, "Sending message to boxstack");
\r
454 boxstack->processMessage(m);
\r
458 void Command::handleCommand(int button)
\r
460 if (isStandby && (button != Remote::POWER)) return;
\r
461 if (!connLost && boxstack->handleCommand(button)) return; // don't send to boxstack if connLost
\r
463 // command was not handled
\r
467 case Remote::DF_LEFT:
\r
468 case Remote::DF_RIGHT:
\r
469 case Remote::VOLUMEUP:
\r
470 case Remote::VOLUMEDOWN:
\r
472 VVolume* v = new VVolume();
\r
474 v->handleCommand(button); // this will draw+show
\r
479 VMute* v = new VMute();
\r
482 boxstack->update(v);
\r
485 case Remote::POWER:
\r
493 if (!connLost) return; // if connLost, handle Remote::OK
\r
494 doFromTheTop(false);
\r
499 VSleeptimer* sleep = new VSleeptimer();
\r
500 boxstack->add(sleep);
\r
501 sleep->handleCommand(button); // this will draw+show
\r
507 void Command::sig1()
\r
510 Message* m = new Message(); // break into master mutex
\r
511 m->message = Message::SCREENSHOT;
\r
517 void Command::doStandby()
\r
521 Video::getInstance()->signalOn();
\r
522 Led::getInstance()->on();
\r
526 VConnect* vconnect = new VConnect(server);
\r
527 boxstack->add(vconnect);
\r
532 boxstack->removeAll();
\r
533 Video::getInstance()->signalOff();
\r
534 boxstack->update(wallpaper);
\r
536 VDR::getInstance()->configSave("General", "Last Power State", "Off");
\r
537 logger->unsetExternLogger();
\r
538 VDR::getInstance()->disconnect();
\r
539 Led::getInstance()->off();
\r
541 Sleeptimer::getInstance()->shutdown();
\r
543 stop(); //different behavoiur on windows, we exit
\r
548 void Command::doFromTheTop(bool which)
\r
554 logger->log("Command", Log::NOTICE, "Connection lost dialog already present");
\r
558 logger->log("Command", Log::NOTICE, "Doing connection lost dialog");
\r
559 connLost = new VInfo();
\r
560 connLost->setSize(360, 200);
\r
561 connLost->createBuffer();
\r
562 if (Video::getInstance()->getFormat() == Video::PAL)
\r
563 connLost->setPosition(190, 170);
\r
565 connLost->setPosition(180, 120);
\r
566 connLost->setOneLiner(tr("Connection lost"));
\r
567 connLost->setDropThrough();
\r
568 connLost->setBorderOn(1);
\r
569 connLost->setTitleBarColour(Colour::DANGER);
\r
570 connLost->okButton();
\r
572 boxstack->add(connLost);
\r
573 boxstack->update(connLost);
\r
574 remote->clearBuffer();
\r
578 logger->unsetExternLogger();
\r
579 VDR::getInstance()->disconnect();
\r
580 boxstack->removeAll();
\r
581 boxstack->update(wallpaper);
\r
584 flushMessageQueue();
\r
585 remote->clearBuffer();
\r
587 // at this point, everything should be reset to first-go
\r
589 VConnect* vconnect = new VConnect(server);
\r
590 boxstack->add(vconnect);
\r
595 void Command::doReboot()
\r
598 logger->unsetExternLogger();
\r
599 VDR::getInstance()->disconnect();
\r
601 logger->log("Command", Log::NOTICE, "Reboot");
\r
603 #ifdef VOMP_PLATTFORM_MVP
\r
604 reboot(LINUX_REBOOT_CMD_RESTART);
\r
613 #endif //Would we support this on windows?
\r
616 void Command::connectionLost()
\r
618 logger->unsetExternLogger();
\r
619 Message* m = new Message(); // break into master mutex
\r
620 m->message = Message::CONNECTION_LOST;
\r
622 postMessageFromOuterSpace(m);
\r
625 void Command::buildCrashedBox()
\r
627 VInfo* crash = new VInfo();
\r
628 crash->setSize(360, 250);
\r
629 crash->createBuffer();
\r
630 if (Video::getInstance()->getFormat() == Video::PAL)
\r
631 crash->setPosition(190, 146);
\r
633 crash->setPosition(180, 96);
\r
634 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.");
\r
635 crash->setBorderOn(1);
\r
636 crash->setTitleBarColour(Colour::DANGER);
\r
638 crash->setExitable();
\r
640 boxstack->add(crash);
\r
641 boxstack->update(crash);
\r
644 void Command::doJustConnected(VConnect* vconnect)
\r
646 I18n::initialize();
\r
647 if (!VDR::getInstance()->isConnected()) { connectionLost(); return; }
\r
649 Video* video = Video::getInstance();
\r
650 Audio* audio = Audio::getInstance();
\r
651 boxstack->remove(vconnect);
\r
653 VInfo* vi = new VInfo();
\r
654 vi->setSize(400, 200);
\r
655 vi->createBuffer();
\r
656 if (video->getFormat() == Video::PAL)
\r
657 vi->setPosition(170, 200);
\r
659 vi->setPosition(160, 150);
\r
660 vi->setOneLiner(tr("Connected, loading config"));
\r
663 boxstack->update(vi);
\r
665 VDR* vdr = VDR::getInstance();
\r
668 // See if we're supposed to do network logging
\r
669 config = vdr->configLoad("Advanced", "Network logging");
\r
670 if (config && !STRCASECMP(config, "On"))
\r
672 logger->log("Command", Log::INFO, "Turning on network logging");
\r
673 logger->setExternLogger(vdr);
\r
677 logger->unsetExternLogger();
\r
678 logger->log("Command", Log::INFO, "Turned off network logging");
\r
680 if (config) delete[] config;
\r
682 // See if config says to override video format (PAL/NTSC)
\r
683 config = vdr->configLoad("General", "Override Video Format");
\r
686 logger->log("Command", Log::DEBUG, "Override Video Format is present");
\r
688 if ( (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
\r
689 || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL)) )
\r
691 // Oh sheesh, need to switch format. Bye bye TV...
\r
693 // Take everything down
\r
694 boxstack->removeAll();
\r
695 boxstack->remove(wallpaper);
\r
696 Osd* osd = Osd::getInstance();
\r
697 #ifndef __ANDROID__
\r
702 // Get video and osd back up with the new mode
\r
703 if (!strcmp(config, "PAL"))
\r
705 logger->log("Command", Log::DEBUG, "Switching to PAL");
\r
706 video->init(Video::PAL);
\r
708 else if (!strcmp(config, "NTSC"))
\r
710 logger->log("Command", Log::DEBUG, "Switching to NTSC");
\r
711 video->init(Video::NTSC);
\r
713 #ifndef __ANDROID__
\r
714 //we do not init twice
\r
715 osd->init((char*)("/dev/stbgfx"));
\r
718 // Put the wallpaper back
\r
721 // Re add the vinfo
\r
723 vi->setSize(400, 200);
\r
724 vi->createBuffer();
\r
725 if (video->getFormat() == Video::PAL)
\r
726 vi->setPosition(170, 200);
\r
728 vi->setPosition(160, 150);
\r
730 vi->setOneLiner(tr("Connected, loading config"));
\r
733 boxstack->update(vi);
\r
737 logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
\r
742 logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
\r
745 // Power off if first boot and config says so
\r
750 logger->log("Command", Log::DEBUG, "Load power after boot");
\r
752 config = vdr->configLoad("General", "Power After Boot");
\r
756 if (!STRCASECMP(config, "On"))
\r
758 logger->log("Command", Log::INFO, "Config says Power After Boot = On");
\r
760 else if (!STRCASECMP(config, "Off"))
\r
762 logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
\r
765 return; // quit here
\r
767 else if (!STRCASECMP(config, "Last state"))
\r
769 char* lastPowerState = vdr->configLoad("General", "Last Power State");
\r
770 if (lastPowerState)
\r
772 if (!STRCASECMP(lastPowerState, "On"))
\r
774 logger->log("Command", Log::INFO, "Config says Last Power State = On");
\r
776 else if (!STRCASECMP(lastPowerState, "Off"))
\r
778 logger->log("Command", Log::INFO, "Config says Last Power State = Off");
\r
781 return; // quit here
\r
785 logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
\r
790 logger->log("Command", Log::INFO, "Config General/Last Power State not found");
\r
795 logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
\r
801 logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
\r
806 // Go S-Video if config says so
\r
808 config = vdr->configLoad("TV", "Connection");
\r
812 if (!STRCASECMP(config, "S-Video"))
\r
814 logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
\r
815 video->setConnection(Video::SVIDEO);
\r
819 logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
\r
820 video->setConnection(Video::COMPOSITERGB);
\r
826 logger->log("Command", Log::INFO, "Config TV/S-Video not found");
\r
831 config = vdr->configLoad("General", "Remote type");
\r
835 if (!STRCASECMP(config, "New"))
\r
837 logger->log("Command", Log::INFO, "Switching to New remote type");
\r
838 remote->setRemoteType(Remote::NEWREMOTE);
\r
842 logger->log("Command", Log::INFO, "Switching to Old remote type");
\r
843 remote->setRemoteType(Remote::OLDREMOTE);
\r
849 logger->log("Command", Log::INFO, "Config General/Remote type not found");
\r
850 remote->setRemoteType(Remote::OLDREMOTE);
\r
856 // Get TV aspect ratio
\r
858 config = vdr->configLoad("TV", "Aspect");
\r
861 if (!STRCASECMP(config, "16:9"))
\r
863 logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
\r
864 video->setTVsize(Video::ASPECT16X9);
\r
868 logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
\r
869 video->setTVsize(Video::ASPECT4X3);
\r
875 logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
\r
876 video->setTVsize(Video::ASPECT4X3);
\r
879 config = vdr->configLoad("TV", "Widemode");
\r
882 if (!STRCASECMP(config, "Letterbox"))
\r
884 logger->log("Command", Log::INFO, "Setting letterbox mode");
\r
885 video->setMode(Video::LETTERBOX);
\r
889 logger->log("Command", Log::INFO, "Setting chop-sides mode");
\r
890 video->setMode(Video::NORMAL);
\r
897 logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting letterbox mode");
\r
898 video->setMode(Video::LETTERBOX);
\r
900 logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
\r
901 video->setMode(Video::NORMAL);
\r
905 config = vdr->configLoad("Advanced", "TCP receive window");
\r
908 size_t newTCPsize = atoi(config);
\r
911 logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
\r
912 vdr->setReceiveWindow(newTCPsize);
\r
916 logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
\r
917 vdr->setReceiveWindow(2048); // Default
\r
920 config = vdr->configLoad("Advanced", "Disable WOL");
\r
923 if (!STRCASECMP(config, "Yes"))
\r
925 logger->log("Command", Log::INFO, "Config says disable WOL");
\r
926 Wol::getInstance()->setEnabled(false);
\r
930 logger->log("Command", Log::INFO, "Config says enable WOL");
\r
931 Wol::getInstance()->setEnabled(true);
\r
938 logger->log("Command", Log::INFO, "By default, enable WOL");
\r
939 Wol::getInstance()->setEnabled(true);
\r
941 /* device dependend config */
\r
942 audio->loadOptionsfromServer(vdr);
\r
943 video->loadOptionsfromServer(vdr);
\r
944 remote->loadOptionsfromServer(vdr);
\r
947 // Save power state = on
\r
949 vdr->configSave("General", "Last Power State", "On");
\r
951 // Make sure connection didn't die
\r
952 if (!vdr->isConnected())
\r
954 Command::getInstance()->connectionLost();
\r
958 boxstack->remove(vi);
\r
960 VWelcome* vw = new VWelcome();
\r
963 boxstack->update(vw);
\r
965 // Enter pre-keys here
\r
966 // handleCommand(Remote::OK);
\r
967 // handleCommand(Remote::THREE);
\r
968 // handleCommand(Remote::SIX);
\r
969 // handleCommand(Remote::OK);
\r
970 // handleCommand(Remote::UP);
\r
971 // handleCommand(Remote::PLAY);
\r
972 // handleCommand(Remote::DOWN);
\r
973 // handleCommand(Remote::DOWN);
\r
974 // handleCommand(Remote::DOWN);
\r
975 // handleCommand(Remote::OK);
\r
976 // handleCommand(Remote::RED);
\r