From 3dcf1a4b91239cbf2cd4386639503083469a9689 Mon Sep 17 00:00:00 2001
From: Chris Tallon <chris@vomp.tv>
Date: Thu, 22 Nov 2007 23:44:42 +0000
Subject: [PATCH] *** empty log message ***

---
 command.cc           |   8 ++
 timers.h             |  46 ++++++++
 vdrresponsepacket.cc |   6 ++
 vdrresponsepacket.h  |   2 +
 vepg.cc              |   6 +-
 vvideolivetv.cc      | 244 +++++++++++++++++++++++++++++++++----------
 vvideolivetv.h       |  14 ++-
 7 files changed, 267 insertions(+), 59 deletions(-)

diff --git a/command.cc b/command.cc
index 528a937..8edb347 100644
--- a/command.cc
+++ b/command.cc
@@ -426,6 +426,14 @@ void Command::processMessage(Message* m)
   }
   else
   {
+    /* FIXME
+    
+    Instead of sending through the boxstack, implement a more generic MessageReceiver interface
+    and have potential receivers register with something
+    When a message needs to be delivered, check if the receiver is still registered, if so, deliver the message
+    This could all be done using the existing big command mutex to keep it simple
+    */
+  
     logger->log("Command", Log::DEBUG, "Sending message to boxstack");
     boxstack->processMessage(m);
   }
diff --git a/timers.h b/timers.h
index 55ddc9a..bdebc40 100755
--- a/timers.h
+++ b/timers.h
@@ -1,3 +1,49 @@
+
+
+
+
+
+
+
+
+
+/*
+
+
+FYI
+
+Timers ... deprecated. Maybe.
+
+This whole thing will be replaced with a timed-message idea. It will be possible
+to send yourself (or whoever) a message with a delay, or delivery time. The message
+will be handed to Command as usual, but command will do the right thing. The messages
+will be delivered to the recipient _with the gui mutex locked_, meaning updates can
+be done there and then in the message handler.
+
+Good points:
+* Cuts down on code lines
+* Most (all?) timercall()s eventually send a message to command in order to
+  do something within The Big Mutex. This makes it easier and simpler code wise
+* Gets rid of Timers.
+* Hopefully gets rid of most postMessageFromOuterSpace calls
+
+Bad points:
+* Timers become gui only features. Solve this with a MessageReceiver interface and
+  have command deliver messages straight to the recipients rather than through BoxStack.
+* Timer delivery accuracy becomes dependant on everything that uses The Big Mutex.
+  It will become more important to not block The Big Mutex.
+* Cancelling timers... hmm
+
+If you have any comments about the new design, like, "It's just as flawed as the old one",
+then I'd appreciate hearing it before I start writing it all :)
+
+
+*/
+
+
+
+
+
 /*
     Copyright 2004-2005 Chris Tallon
 
diff --git a/vdrresponsepacket.cc b/vdrresponsepacket.cc
index 3f3810e..e9ca08b 100644
--- a/vdrresponsepacket.cc
+++ b/vdrresponsepacket.cc
@@ -21,6 +21,7 @@
 #include "vdrresponsepacket.h"
 
 #include "vdr.h"
+#include "tcp.h"
 
 VDR_ResponsePacket::VDR_ResponsePacket()
 {
@@ -63,6 +64,11 @@ bool VDR_ResponsePacket::end()
   return (packetPos >= userDataLength);
 }
 
+void VDR_ResponsePacket::dumpUD()
+{
+  TCP::dump(userData, userDataLength);
+}
+
 int VDR_ResponsePacket::serverError()
 {
   if ((packetPos == 0) && (userDataLength == 4) && !ntohl(*(ULONG*)userData)) return 1;
diff --git a/vdrresponsepacket.h b/vdrresponsepacket.h
index e37edd6..dc35869 100644
--- a/vdrresponsepacket.h
+++ b/vdrresponsepacket.h
@@ -52,6 +52,8 @@ class VDR_ResponsePacket
 
     bool end();
 
+    void dumpUD();
+
     // Do this a better way?
     UCHAR* getBlock_getUserData();
 
diff --git a/vepg.cc b/vepg.cc
index 4982be3..a12cf85 100644
--- a/vepg.cc
+++ b/vepg.cc
@@ -428,7 +428,7 @@ int VEpg::handleCommand(int command)
       if (!chanList) return 2;
 
       // select programme and display menu TODO currently just changes to selected channel
-      videoLive->channelChange(VVideoLive::NUMBER, (*chanList)[chanListbox.getCurrentOption()]->number);
+      if (videoLive) videoLive->channelChange(VVideoLive::NUMBER, (*chanList)[chanListbox.getCurrentOption()]->number);
 
       if(command == Remote::GO)
         return 2;
@@ -450,12 +450,12 @@ int VEpg::handleCommand(int command)
     }
     case Remote::CHANNELUP:
     {
-      videoLive->channelChange(VVideoLive::OFFSET, VVideoLive::UP);
+      if (videoLive) videoLive->channelChange(VVideoLive::OFFSET, VVideoLive::UP);
       return 2;
     }
     case Remote::CHANNELDOWN:
     {
-      videoLive->channelChange(VVideoLive::OFFSET, VVideoLive::DOWN);
+      if (videoLive) videoLive->channelChange(VVideoLive::OFFSET, VVideoLive::DOWN);
       return 2;
     }
   }
diff --git a/vvideolivetv.cc b/vvideolivetv.cc
index e9a387d..a698eb6 100644
--- a/vvideolivetv.cc
+++ b/vvideolivetv.cc
@@ -34,6 +34,8 @@
 #include "vaudioselector.h"
 #include "colour.h"
 #include "event.h"
+#include "timers.h"
+#include "vepg.h"
 
 VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, VChannelList* tvchannelList)
 {
@@ -50,6 +52,8 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V
   osdChannelIndex = 0;
   keying = 0;
 
+  playing = false;
+
   // Convert channel number to index
   UINT i;
   for(i = 0; i < chanList->size(); i++)
@@ -105,7 +109,6 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V
   clock.setBackgroundColour(Colour::BLACK);
   clock.setPosition(osd.getWidth() - 100, 4);
   clock.setSize(90, 30);
-  clock.setText("00:00");
   osd.add(&clock);
 
   osdChanNum.setBackgroundColour(Colour::BLACK);
@@ -170,6 +173,8 @@ VVideoLiveTV::VVideoLiveTV(ChannelList* tchanList, ULONG initialChannelNumber, V
 
 VVideoLiveTV::~VVideoLiveTV()
 {
+  if (playing) stop();
+
 //  delete player;
   video->setDefaultAspect();
 }
@@ -178,8 +183,16 @@ int VVideoLiveTV::handleCommand(int command)
 {
   switch(command)
   {
-    case Remote::STOP:
     case Remote::BACK:
+    {
+      if (osd.getVisible())
+      {
+        removeOSD();
+        return 2;
+      }
+      // else drop through to stop
+    }
+    case Remote::STOP:
     case Remote::MENU:
     {
       stop();
@@ -190,18 +203,14 @@ int VVideoLiveTV::handleCommand(int command)
     {
       // New remote only
       // epg data up
-      sl.up();
-      sl.draw();
-      boxstack->update(this, osd.getRegion());
+      doUp();
       return 2;
     }
     case Remote::DOWN:
     {
       // New remote only
       // epg data down
-      sl.down();
-      sl.draw();
-      boxstack->update(this, osd.getRegion());
+      doDown();
       return 2;
     }
     case Remote::LEFT:
@@ -240,7 +249,6 @@ int VVideoLiveTV::handleCommand(int command)
       doOK();
       return 2;
     }
-    case Remote::GUIDE:
     case Remote::RED:
     {
       return 2;
@@ -279,14 +287,16 @@ int VVideoLiveTV::handleCommand(int command)
       BoxStack::getInstance()->update(vas);        
       */
     }
-#ifdef DEV
     case Remote::YELLOW:
     {
+      return 2;
     }
+    case Remote::GUIDE:
     case Remote::BLUE:
     {
+      doEPG();
+      return 2;
     }
-#endif
   }
 
   return 1;
@@ -294,17 +304,21 @@ int VVideoLiveTV::handleCommand(int command)
 
 void VVideoLiveTV::go()
 {
-  doNowNext();
-  osd.setVisible(true);
+  playing = true;
   draw();
   boxstack->update(this);
-  // set a timer for osd deletion
 
+  setClock();
+  displayOSD();
+  
   // start player  
 }
 
 void VVideoLiveTV::stop()
-{  
+{
+  Timers::getInstance()->cancelTimer(this, 1);
+  Timers::getInstance()->cancelTimer(this, 2);
+  playing = false;
 }
 
 void VVideoLiveTV::doNowNext()
@@ -372,87 +386,106 @@ void VVideoLiveTV::doOK()
 {
   if (osd.getVisible())
   {
-    if (osdChannelIndex == currentChannelIndex)
+    if (keying)
     {
-      osd.setVisible(false);
-      draw();
-      boxstack->update(this, osd.getRegion());
+      UINT newChannel = 0;
+      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
+      
+      channelChange(NUMBER, newChannel);
+      osdChannelIndex = currentChannelIndex;
+      displayOSD();
+    }
+    else if (osdChannelIndex == currentChannelIndex)
+    {
+      removeOSD();
     }
     else
     {
       channelChange(INDEX, osdChannelIndex);
-      doNowNext();
-      draw();
-      boxstack->update(this, osd.getRegion());
+      displayOSD();
     }
   }
   else
   {
     osdChannelIndex = currentChannelIndex;
-    doNowNext();
-    osd.setVisible(true);
-    draw();
-    boxstack->update(this, osd.getRegion());
-    // set a timer for deletion of osd
+    displayOSD();
   }
 }
 
 void VVideoLiveTV::doLeft()
 {
   if (osd.getVisible())
-  {
     osdChannelIndex = downChannel(osdChannelIndex);
-  }
   else
-  {
     osdChannelIndex = currentChannelIndex;
-    osd.setVisible(true);
-  }    
 
-  doNowNext();
-  draw();
-  boxstack->update(this, osd.getRegion());     
+  displayOSD();
 }
 
 void VVideoLiveTV::doRight()
 {
   if (osd.getVisible())
-  {
     osdChannelIndex = upChannel(osdChannelIndex);
+  else
+    osdChannelIndex = currentChannelIndex;
+
+  displayOSD();
+}
+
+void VVideoLiveTV::doUp()
+{
+  if (osd.getVisible())
+  {
+    sl.up();
+    sl.draw();
+    boxstack->update(this, osd.getRegion());
+    Timers::getInstance()->setTimerD(this, 1, 8);  // arrows pressed, go to 8s timer
   }
   else
   {
-    osdChannelIndex = currentChannelIndex;
-    osd.setVisible(true);
-  }    
+    displayOSD();
+  }
+}
 
-  doNowNext();
-  draw();
-  boxstack->update(this, osd.getRegion());  
+void VVideoLiveTV::doDown()
+{
+  if (osd.getVisible())
+  {
+    sl.down();
+    sl.draw();
+    boxstack->update(this, osd.getRegion());
+    Timers::getInstance()->setTimerD(this, 1, 8);  // arrows pressed, go to 8s timer
+  }
+  else
+  {
+    displayOSD();
+  }
 }
 
 void VVideoLiveTV::doChanUp()
 {
   channelChange(OFFSET, UP);
   osdChannelIndex = currentChannelIndex;
-  doNowNext();
-  draw();
-  boxstack->update(this, osd.getRegion());     
+
+  displayOSD();
 }
 
 void VVideoLiveTV::doChanDown()
 {
   channelChange(OFFSET, DOWN);
   osdChannelIndex = currentChannelIndex;
-  doNowNext();
-  draw();
-  boxstack->update(this, osd.getRegion());   
+
+  displayOSD();
 }
 
 void VVideoLiveTV::doKey(int command)
 {
+  if (!osd.getVisible()) // First key. prep the data
+  {
+    doNowNext();
+  }
+
   int i;
-  
   for (i = keying - 1; i >= 0; i--) keyingInput[i+1] = keyingInput[i];
   keyingInput[0] = command;
   keying++;
@@ -470,15 +503,116 @@ void VVideoLiveTV::doKey(int command)
     
     channelChange(NUMBER, newChannel);
     osdChannelIndex = currentChannelIndex;
-    doNowNext();
-    draw();
-    boxstack->update(this, osd.getRegion());
+    displayOSD();
   }
   else
   {
-    osdChanNum.setText(keyingString);
-    osdChanNum.draw();  
+    // Special, modified displayOSD
+    if (!osd.getVisible())
+    {
+      osd.setVisible(true);
+      osdChanNum.setText(keyingString);
+      draw();
+    }
+    else
+    {
+      osdChanNum.setText(keyingString);
+      osdChanNum.draw();
+    }
     boxstack->update(this, osd.getRegion());
+    Timers::getInstance()->setTimerD(this, 1, 3);  // 3s for keying input
+  }
+}
+
+void VVideoLiveTV::displayOSD()
+{
+  osd.setVisible(true);
+  doNowNext();
+  draw();
+  boxstack->update(this, osd.getRegion());
+  Timers::getInstance()->setTimerD(this, 1, 4);
+}
+
+void VVideoLiveTV::removeOSD()
+{  
+  Timers::getInstance()->cancelTimer(this, 1);
+  osd.setVisible(false);
+  draw();
+  boxstack->update(this, osd.getRegion());
+}
+
+void VVideoLiveTV::setClock()
+{
+  char timeString[20];
+  time_t t;
+  time(&t);
+  struct tm* tms = localtime(&t);
+  strftime(timeString, 19, "%H:%M", tms);
+  clock.setText(timeString);
+
+  time_t dt = 60 - (t % 60);  // seconds to the next minute
+  if (dt == 0) dt = 60; // advance a whole minute if necessary
+  dt += t;  // get a time_t value for it rather than using duration
+  // (so it will occur at the actual second and not second and a half)
+
+  Timers::getInstance()->setTimerT(this, 2, dt);
+}
+
+void VVideoLiveTV::doEPG()
+{
+  if (osd.getVisible()) removeOSD();
+
+  video->setMode(Video::QUARTER);
+  video->setPosition(170, 5); //TODO need to deal with 4:3 switching
+
+  VEpg* vepg = new VEpg(NULL, currentChannelIndex, VDR::VIDEO);
+  vepg->draw();
+  boxstack->add(vepg);
+  boxstack->update(vepg);
+}
+
+void VVideoLiveTV::timercall(int ref)
+{
+  if (ref == 1)
+  {
+    if (keying)
+    {
+      // Really, now that cancelTimer basically protects us from deletion, why can't we execute gui stuff here?
+      
+      UINT newChannel = 0;
+      for(int i = keying - 1; i >= 0; i--) newChannel += keyingInput[i] * (ULONG)pow(10, i);
+      
+      Message* m = new Message();
+      m->message = Message::CHANNEL_CHANGE;
+      m->to = this;
+      m->parameter = newChannel;
+      Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.
+    }
+    else
+    {
+      osd.setVisible(false);
+      draw();
+      Message* m = new Message();
+      m->message = Message::REDRAW;
+      m->to = BoxStack::getInstance();
+      m->from = this;
+      m->parameter = (ULONG)osd.getRegion();
+      Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.
+    }
+  }
+  else if (ref == 2)
+  {
+    setClock();
+    if (osd.getVisible())
+    {
+      clock.draw();
+      Message* m = new Message();
+      m->message = Message::REDRAW;
+      m->to = BoxStack::getInstance();
+      m->from = this;
+      m->parameter = (ULONG)osd.getRegion();
+      Command::getInstance()->postMessageFromOuterSpace(m);  // FIXME cjt yeah you know what.    
+    }
   }
 }
 
@@ -542,6 +676,8 @@ void VVideoLiveTV::processMessage(Message* m)
   else if (m->message == Message::CHANNEL_CHANGE)
   {
     channelChange(NUMBER, m->parameter);
+    osdChannelIndex = currentChannelIndex;
+    displayOSD();
   }
   else if (m->message == Message::EPG_CLOSE)
   {
diff --git a/vvideolivetv.h b/vvideolivetv.h
index 26a2a79..23799bd 100644
--- a/vvideolivetv.h
+++ b/vvideolivetv.h
@@ -31,8 +31,8 @@
 #include "vdr.h"
 #include "wtextbox.h"
 #include "wselectlist.h"
+#include "timerreceiver.h"
 
-class VEpg;
 class VChannelList;
 class Video;
 class VChannelList;
@@ -40,7 +40,7 @@ class BoxStack;
 class WTextbox;
 //class PlayerLiveTV;
 
-class VVideoLiveTV : public Boxx
+class VVideoLiveTV : public Boxx, public TimerReceiver
 {
   public:
     VVideoLiveTV(ChannelList* chanList, ULONG initialChannelNumber, VChannelList* vchannelList);
@@ -62,11 +62,14 @@ class VVideoLiveTV : public Boxx
     const static UCHAR UP = 1;
     const static UCHAR DOWN = 2;
 
+    void timercall(int ref);
+
   private:
     BoxStack* boxstack;
     VDR* vdr;
     Video* video;
 //    PlayerLiveTV* player;
+    bool playing;
     ChannelList* chanList;
     VChannelList* vchannelList;
     EventList* eventList;
@@ -88,9 +91,15 @@ class VVideoLiveTV : public Boxx
     void doOK();
     void doLeft();
     void doRight();
+    void doUp();
+    void doDown();
     void doChanUp();
     void doChanDown();
     void doKey(int command);
+    void displayOSD();
+    void removeOSD();
+    void setClock();
+    void doEPG();
 
     Wwss wss;
     Region wssRegion;
@@ -109,6 +118,7 @@ class VVideoLiveTV : public Boxx
     WTextbox textGreen;
     WTextbox textYellow;
     WTextbox textBlue;
+
 };
 
 #endif
-- 
2.39.5