]> git.vomp.tv Git - vompclient.git/blob - command.cc
Language changes, fix for main menu hang
[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 "command.h"
22 #ifdef WIN32
23 #include "remotewin.h"
24 #endif
25
26 Command* Command::instance = NULL;
27
28 Command::Command()
29 {
30   if (instance) return;
31   instance = this;
32   initted = 0;
33   isStandby = 0;
34   firstBoot = 1;
35   connLost = NULL;
36 }
37
38 Command::~Command()
39 {
40   instance = NULL;
41 }
42
43 Command* Command::getInstance()
44 {
45   return instance;
46 }
47
48 int Command::init()
49 {
50   if (initted) return 0;
51   initted = 1;
52
53   logger = Log::getInstance();
54   viewman = ViewMan::getInstance();
55   remote = Remote::getInstance();
56
57   if (!logger || !viewman || !remote)
58   {
59     initted = 0;
60     return 0;
61   }
62 #ifndef WIN32
63   pthread_mutex_init(&masterLock, NULL);
64 #else
65   masterLock=CreateMutex(NULL,FALSE,NULL);
66 #endif
67
68   return 1;
69 }
70
71 int Command::shutdown()
72 {
73   if (!initted) return 0;
74   initted = 0;
75   return 1;
76 }
77
78 void Command::stop()
79 {
80 //  VDR::getInstance()->cancelFindingServer();
81   irun = 0;
82 }
83
84 void Command::doWallpaper()
85 {
86   Video* video = Video::getInstance();
87
88   // Blue background
89   View* v = new View();
90   v->create(video->getScreenWidth(), video->getScreenHeight());
91   v->setBackgroundColour(Colour::VIDEOBLUE);
92   v->draw();
93   viewman->add(v);
94   viewman->updateView(v);
95   viewman->removeView(v);
96
97   // Wallpaper
98   wallpaper = new VWallpaper();
99   if (video->getFormat() == Video::PAL)
100   {
101     logger->log("Command", Log::DEBUG, "PAL wallpaper selected");
102     wallpaper->init("/wallpaperPAL.jpg");
103   }
104   else
105   {
106     logger->log("Command", Log::DEBUG, "NTSC wallpaper selected");
107     wallpaper->init("/wallpaperNTSC.jpg");
108   }
109   wallpaper->draw();
110   viewman->add(wallpaper);
111   viewman->updateView(wallpaper);
112 }
113
114 void Command::run()
115 {
116   if (!initted) return;
117   irun = 1;
118 #ifndef WIN32
119   mainPid = getpid();
120 #endif
121
122   // just in case
123   Video::getInstance()->signalOn();
124   Led::getInstance()->on();
125
126   doWallpaper();
127
128   // End of startup. Lock the mutex and put the first view up
129 #ifndef WIN32
130   pthread_mutex_lock(&masterLock);
131 #else
132   WaitForSingleObject(masterLock, INFINITE );
133 #endif
134   VConnect* vconnect = new VConnect();
135   viewman->add(vconnect);
136   vconnect->run();
137
138   UCHAR button = 0;
139   while(irun)
140   {
141     // unlock and wait
142 #ifndef WIN32
143     pthread_mutex_unlock(&masterLock);
144 #else
145     ReleaseMutex(masterLock);
146 #endif
147     button = remote->getButtonPress(2);  // FIXME why is this set to 2 and not 0? so it can quit
148     // something happened, lock and process
149
150 #ifndef WIN32
151     pthread_mutex_lock(&masterLock);
152 #else
153     WaitForSingleObject(masterLock, INFINITE );
154 #endif
155
156     if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue;
157
158     if (button != Remote::NA_SIGNAL) handleCommand(button);
159     processMessageQueue();
160   }
161
162 #ifndef WIN32
163   pthread_mutex_unlock(&masterLock);
164 #else
165   ReleaseMutex(masterLock);
166 #endif
167 }
168
169 void Command::postMessage(Message* m)
170 {
171   // This is locked here in case the main loop is not waiting for an event, but is processing one
172   // it could be killed but then not react to it because the signal wouldn't cause
173   // remote->getButtonPress to break
174   // locking the mutex ensures that the master thread is waiting on getButtonPress
175
176
177 #ifndef WIN32
178   pthread_mutex_lock(&masterLock);
179 #else
180   WaitForSingleObject(masterLock, INFINITE );
181 #endif
182   MessageQueue::postMessage(m);
183
184 #ifndef WIN32
185   kill(mainPid, SIGURG);
186   pthread_mutex_unlock(&masterLock);
187 #else
188   ((RemoteWin*)Remote::getInstance())->Signal();
189   ReleaseMutex(masterLock);
190 #endif
191 }
192
193 void Command::postMessageNoLock(Message* m)
194 {
195   // As above but use this one if this message is being posted because of a button press
196   // the mutex is already locked, locking around postMessage is not needed as the
197   // queue is guaranteed to be run when the button has been processed
198   MessageQueue::postMessage(m);
199 }
200
201 bool Command::postMessageIfNotBusy(Message* m)
202 {
203   // This is for the timers module
204   // If the masterlock is locked then the timers module wants to
205   // cancel delivery
206 #ifndef WIN32
207   if (pthread_mutex_trylock(&masterLock) != EBUSY)
208   {
209     MessageQueue::postMessage(m);
210     kill(mainPid, SIGURG);
211     pthread_mutex_unlock(&masterLock);
212     return true;
213   }
214   else
215   {
216     return false;
217   }
218 #else
219   switch (WaitForSingleObject(masterLock, 0 ))
220   { //FIXME this is not "if not busy" check
221     case WAIT_OBJECT_0: //but with proper argument 0 this did not work
222     // case WAIT_ABANDONED:
223     MessageQueue::postMessage(m);
224     ((RemoteWin*)Remote::getInstance())->Signal();
225     ReleaseMutex(masterLock);
226     return true;
227
228     case WAIT_ABANDONED: return false;
229     case WAIT_TIMEOUT: return false;
230   }
231     return false;
232 #endif
233 }
234
235 void Command::processMessage(Message* m)
236 {
237   logger->log("Command", Log::DEBUG, "processing message %i", m->message);
238
239   switch(m->message)
240   {
241     case Message::STANDBY:
242     {
243       doStandby();
244       break;
245     }
246     case Message::STOP_PLAYBACK:
247     {
248       handleCommand(Remote::STOP); // an odd way of doing it, but so simple
249       break;
250     }
251     case Message::STREAM_END:
252     {
253       VVideoLive::getInstance()->streamEnd();
254       break;
255     }
256     case Message::VDR_CONNECTED:
257     {
258       doJustConnected((VConnect*)m->from);
259       break;
260     }
261     case Message::TIMER:
262     {
263       // FIXME - go to one message queue only - then instead of having
264       // objects deriving from messagequeues, make them derive from
265       // messagereceiver - then one messagequeue can deliver any message to anywhere
266
267       // deliver timer
268
269       ((TimerReceiver*)m->to)->timercall(m->parameter);
270       handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
271                                       // run viewman message queue here. FIXME improve this!
272       break;
273     }
274     case Message::SCREENSHOT:
275     {
276       Osd::getInstance()->screenShot("/out.jpg");
277       break;
278     }
279     case Message::CONNECTION_LOST:
280     {
281       doFromTheTop(true);
282       break;
283     }
284   }
285 }
286
287 void Command::handleCommand(int button)
288 {
289   if (isStandby && (button != Remote::POWER)) return;
290
291   if (!connLost && viewman->handleCommand(button)) return; // don't send to viewman if connLost
292
293   // command was not handled
294
295   switch(button)
296   {
297     case Remote::DF_LEFT:
298     case Remote::DF_RIGHT:
299     case Remote::VOLUMEUP:
300     case Remote::VOLUMEDOWN:
301     {
302       VVolume* v = new VVolume();
303       viewman->add(v);
304       v->handleCommand(button); // this will draw+show
305       return;
306     }
307     case Remote::MUTE:
308     {
309       VMute* v = new VMute();
310       v->draw();
311       viewman->add(v);
312       viewman->updateView(v);
313       return;
314     }
315     case Remote::POWER:
316     {
317       doStandby();
318       return;
319     }
320     case Remote::OK:
321     {
322       if (!connLost) return; // if connLost, handle Remote::OK
323       doFromTheTop(false);
324       return;
325     }
326   }
327 }
328
329 void Command::sig1()
330 {
331 #ifdef DEV
332   Message* m = new Message(); // break into master mutex
333   m->message = Message::SCREENSHOT;
334   m->to = this;
335   postMessage(m);
336 #endif
337 }
338
339 void Command::doStandby()
340 {
341   if (isStandby)
342   {
343     Video::getInstance()->signalOn();
344     Led::getInstance()->on();
345     isStandby = 0;
346
347
348     VConnect* vconnect = new VConnect();
349     viewman->add(vconnect);
350     vconnect->run();
351   }
352   else
353   {
354     viewman->removeAll();
355     Video::getInstance()->signalOff();
356     viewman->updateView(wallpaper);
357
358     VDR::getInstance()->configSave("General", "Last Power State", "Off");
359     VDR::getInstance()->disconnect();
360     Led::getInstance()->off();
361     isStandby = 1;
362   }
363 }
364
365 void Command::doFromTheTop(bool which)
366 {
367   if (which)
368   {
369     connLost = new VInfo();
370     connLost->create(360, 200);
371     if (Video::getInstance()->getFormat() == Video::PAL)
372       connLost->setScreenPos(190, 170);
373     else
374       connLost->setScreenPos(180, 120);
375     connLost->setOneLiner(tr("Connection lost"));
376     connLost->setDropThrough();
377     connLost->setBorderOn(1);
378     connLost->setTitleBarColour(Colour::DANGER);
379     connLost->okButton();
380     connLost->draw();
381     viewman->add(connLost);
382     viewman->updateView(connLost);
383     remote->clearBuffer();
384   }
385   else
386   {
387     VDR::getInstance()->disconnect();
388     viewman->removeAll();
389     viewman->updateView(wallpaper);
390     connLost = NULL;
391     VConnect* vconnect = new VConnect();
392     viewman->add(vconnect);
393     vconnect->run();
394   }
395 }
396
397 void Command::doReboot()
398 {
399   VDR::getInstance()->disconnect();
400   // just kill it...
401   logger->log("Command", Log::NOTICE, "Reboot");
402 #ifndef WIN32
403   reboot(LINUX_REBOOT_CMD_RESTART);
404 #endif //Would we support this on windows?
405 }
406
407 void Command::connectionLost()
408 {
409   Message* m = new Message(); // break into master mutex
410   m->message = Message::CONNECTION_LOST;
411   m->to = this;
412   postMessageNoLock(m);
413 }
414
415 void Command::doJustConnected(VConnect* vconnect)
416 {
417   I18n::initialize();
418   Video* video = Video::getInstance();
419   viewman->removeView(vconnect);
420
421   VInfo* vi = new VInfo();
422   vi->create(400, 200);
423   if (video->getFormat() == Video::PAL)
424     vi->setScreenPos(170, 200);
425   else
426     vi->setScreenPos(160, 150);
427
428   vi->setOneLiner(tr("Connected, loading config"));
429   vi->draw();
430   viewman->add(vi);
431   viewman->updateView(vi);
432
433   VDR* vdr = VDR::getInstance();
434   char* config;
435
436   // See if config says to override video format (PAL/NTSC)
437   config = vdr->configLoad("General", "Override Video Format");
438   if (config)
439   {
440     logger->log("Command", Log::DEBUG, "Override Video Format is present");
441
442     if (   (!strcmp(config, "PAL") && (video->getFormat() == Video::NTSC))
443         || (!strcmp(config, "NTSC") && (video->getFormat() == Video::PAL))  )
444     {
445       // Oh sheesh, need to switch format. Bye bye TV...
446
447       // Take everything down
448       viewman->removeAll();
449       viewman->removeView(wallpaper);
450       Osd* osd = Osd::getInstance();
451       osd->shutdown();
452       video->shutdown();
453
454       // Get video and osd back up with the new mode
455       if (!strcmp(config, "PAL"))
456       {
457         logger->log("Command", Log::DEBUG, "Switching to PAL");
458         video->init(Video::PAL);
459       }
460       else if (!strcmp(config, "NTSC"))
461       {
462         logger->log("Command", Log::DEBUG, "Switching to NTSC");
463         video->init(Video::NTSC);
464       }
465       osd->init((char*)("/dev/stbgfx"));
466
467       // Put the wallpaper back
468       doWallpaper();
469
470       // Re add the vinfo
471       vi = new VInfo();
472       vi->create(400, 200);
473       if (video->getFormat() == Video::PAL)
474         vi->setScreenPos(170, 200);
475       else
476         vi->setScreenPos(160, 150);
477
478       vi->setOneLiner(tr("Connected, loading config"));
479       vi->draw();
480       viewman->add(vi);
481       viewman->updateView(vi);
482     }
483     else
484     {
485       logger->log("Command", Log::DEBUG, "Already in requested mode, or request was not 'PAL' or 'NTSC'");
486     }
487   }
488   else
489   {
490     logger->log("Command", Log::DEBUG, "Phew, no dangerous on-the-fly mode switching to do!");
491   }
492
493   // Power off if first boot and config says so
494   if (firstBoot)
495   {
496     firstBoot = 0;
497
498     logger->log("Command", Log::DEBUG, "Load power after boot");
499
500     config = vdr->configLoad("General", "Power After Boot");
501
502     if (config)
503     {
504       if (!STRCASECMP(config, "On"))
505       {
506         logger->log("Command", Log::INFO, "Config says Power After Boot = On");
507       }
508       else if (!STRCASECMP(config, "Off"))
509       {
510         logger->log("Command", Log::INFO, "Config says Power After Boot = Off");
511         doStandby();
512         delete[] config;
513         return; // quit here
514       }
515       else if (!STRCASECMP(config, "Last state"))
516       {
517         char* lastPowerState = vdr->configLoad("General", "Last Power State");
518         if (lastPowerState)
519         {
520           if (!STRCASECMP(lastPowerState, "On"))
521           {
522             logger->log("Command", Log::INFO, "Config says Last Power State = On");
523           }
524           else if (!STRCASECMP(lastPowerState, "Off"))
525           {
526             logger->log("Command", Log::INFO, "Config says Last Power State = Off");
527             doStandby();
528             delete[] config;
529             return; // quit here
530           }
531           else
532           {
533             logger->log("Command", Log::INFO, "Config General/Last Power State not understood");
534           }
535         }
536         else
537         {
538           logger->log("Command", Log::INFO, "Config General/Last Power State not found");
539         }
540       }
541       else
542       {
543         logger->log("Command", Log::INFO, "Config/Power After Boot not understood");
544       }
545       delete[] config;
546     }
547     else
548     {
549       logger->log("Command", Log::INFO, "Config General/Power After Boot not found");
550     }
551   }
552
553
554   // Go S-Video if config says so
555
556   config = vdr->configLoad("TV", "Connection");
557
558   if (config)
559   {
560     if (!STRCASECMP(config, "S-Video"))
561     {
562       logger->log("Command", Log::INFO, "Switching to S-Video as Connection=%s", config);
563       video->setConnection(Video::SVIDEO);
564     }
565     else
566     {
567       logger->log("Command", Log::INFO, "Switching to RGB/Composite as Connection=%s", config);
568       video->setConnection(Video::COMPOSITERGB);
569     }
570     delete[] config;
571   }
572   else
573   {
574     logger->log("Command", Log::INFO, "Config TV/S-Video not found");
575   }
576
577   // Set remote type
578
579   config = vdr->configLoad("General", "Remote type");
580
581   if (config)
582   {
583     if (!STRCASECMP(config, "New"))
584     {
585       logger->log("Command", Log::INFO, "Switching to New remote type");
586       remote->setRemoteType(Remote::NEWREMOTE);
587     }
588     else
589     {
590       logger->log("Command", Log::INFO, "Switching to Old remote type");
591       remote->setRemoteType(Remote::OLDREMOTE);
592     }
593     delete[] config;
594   }
595   else
596   {
597     logger->log("Command", Log::INFO, "Config General/Remote type not found");
598     remote->setRemoteType(Remote::OLDREMOTE);
599   }
600
601   // Get TV aspect ratio
602
603   config = vdr->configLoad("TV", "Aspect");
604   if (config)
605   {
606     if (!STRCASECMP(config, "16:9"))
607     {
608       logger->log("Command", Log::INFO, "/// Switching to TV aspect 16:9");
609       video->setTVsize(Video::ASPECT16X9);
610     }
611     else
612     {
613       logger->log("Command", Log::INFO, "/// Switching to TV aspect 4:3");
614       video->setTVsize(Video::ASPECT4X3);
615     }
616     delete[] config;
617   }
618   else
619   {
620     logger->log("Command", Log::INFO, "Config TV/Aspect type not found, going 4:3");
621     video->setTVsize(Video::ASPECT4X3);
622   }
623
624   config = vdr->configLoad("TV", "Widemode");
625   if (config)
626   {
627     if (!STRCASECMP(config, "Letterbox"))
628     {
629       logger->log("Command", Log::INFO, "Setting letterbox mode");
630       video->setMode(Video::LETTERBOX);
631     }
632     else
633     {
634       logger->log("Command", Log::INFO, "Setting chop-sides mode");
635       video->setMode(Video::NORMAL);
636     }
637     delete[] config;
638   }
639   else
640   {
641     logger->log("Command", Log::INFO, "Config TV/Widemode not found, Setting chop-sides mode");
642     video->setMode(Video::NORMAL);
643   }
644
645   config = vdr->configLoad("Advanced", "TCP receive window");
646   if (config)
647   {
648     size_t newTCPsize = atoi(config);
649     delete[] config;
650
651     logger->log("Command", Log::INFO, "Setting TCP window size %i", newTCPsize);
652     vdr->setReceiveWindow(newTCPsize);
653   }
654   else
655   {
656     logger->log("Command", Log::INFO, "TCP window size not found, setting 2048");
657     vdr->setReceiveWindow(2048); // Default
658   }
659
660
661   // config done
662
663   // Save power state = on
664
665   vdr->configSave("General", "Last Power State", "On");
666
667   // Make sure connection didn't die
668   if (!vdr->isConnected())
669   {
670     Command::getInstance()->connectionLost();
671   }
672   else
673   {
674     viewman->removeView(vi);
675
676     VWelcome* vw = new VWelcome();
677     vw->draw();
678     viewman->add(vw);
679     viewman->updateView(vw);
680
681     // Enter pre-keys here
682 //    handleCommand(Remote::THREE);
683 //    handleCommand(Remote::SKIPFORWARD);
684 //    handleCommand(Remote::OK);
685 //    handleCommand(Remote::PLAY);
686   }
687 }