{
// unlock and wait
pthread_mutex_unlock(&masterLock);
+ logger->log("Command", Log::DEBUG, "un-LOCKED MASTER MUTEX");
button = remote->getButtonPress(2); // FIXME why is this set to 2 and not 0? so it can quit
// something happened, lock and process
pthread_mutex_lock(&masterLock);
+ logger->log("Command", Log::DEBUG, "LOCKED MASTER MUTEX");
if ((button == Remote::NA_NONE) || (button == Remote::NA_UNKNOWN)) continue;
// locking the mutex ensures that the master thread is waiting on getButtonPress
pthread_mutex_lock(&masterLock);
+ logger->log("Command", Log::DEBUG, "LOCKED MASTER MUTEX");
MessageQueue::postMessage(m);
kill(mainPid, SIGURG);
pthread_mutex_unlock(&masterLock);
+ logger->log("Command", Log::DEBUG, "un-LOCKED MASTER MUTEX");
+}
+
+bool Command::postMessageIfNotBusy(Message* m)
+{
+ // This is for the timers module
+ // If the masterlock is locked then the timers module wants to
+ // cancel delivery
+
+ if (pthread_mutex_trylock(&masterLock) != EBUSY)
+ {
+ logger->log("Command", Log::DEBUG, "LOCKED MASTER MUTEX");
+ MessageQueue::postMessage(m);
+ kill(mainPid, SIGURG);
+ pthread_mutex_unlock(&masterLock);
+ logger->log("Command", Log::DEBUG, "un-LOCKED MASTER MUTEX");
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
void Command::processMessage(Message* m)
// deliver timer
+
+ logger->log("Command", Log::DEBUG, "m = %p", m);
+ logger->log("Command", Log::DEBUG, "m->message = %i", m->message);
+ logger->log("Command", Log::DEBUG, "m->from = %p", m->from);
+ logger->log("Command", Log::DEBUG, "m->to = %p", m->to);
+ logger->log("Command", Log::DEBUG, "m->parameter = %p", m->parameter);
((TimerReceiver*)m->to)->timercall(m->parameter);
handleCommand(Remote::NA_NONE); // in case any timer has posted messages to viewman,
// run viewman message queue here. FIXME improve this!
{
I18n::initialize();
Video* video = Video::getInstance();
- viewman->removeView(vconnect, 0);
+ viewman->removeView(vconnect);
VInfo* vi = new VInfo();
vi->create(400, 200);
void stop();
void doReboot();
void postMessage(Message* m); // override of MessageQueue::postMessage
+ bool postMessageIfNotBusy(Message* m); // for timers, when masterMutex might be locked
private:
void handleCommand(int);
#include "remote.h"
#include "led.h"
#include "mtd.h"
+#include "timers.h"
#include "video.h"
#include "audio.h"
#include "vdr.h"
Mtd* mtd;
Led* led;
Osd* osd;
+Timers* timers;
ViewMan* viewman;
Command* command;
VDR* vdr;
remote = new Remote();
mtd = new Mtd();
led = new Led();
+ timers = new Timers();
osd = new Osd();
vdr = new VDR();
video = new Video();
shutdown(1);
}
+ success = timers->init();
+ if (success)
+ {
+ logger->log("Core", Log::INFO, "Timers module initialised");
+ }
+ else
+ {
+ logger->log("Core", Log::EMERG, "Timers module failed to initialise");
+ shutdown(1);
+ }
+
UCHAR videoFormat = (UCHAR)mtd->getPALorNTSC();
if (videoFormat == Video::PAL) logger->log("Core", Log::INFO, "Read from MTD: PAL 720x576");
else if (videoFormat == Video::NTSC) logger->log("Core", Log::INFO, "Read from MTD: NTSC 720x480");
logger->log("Core", Log::NOTICE, "Video module shut down");
}
+ if (timers)
+ {
+ timers->shutdown();
+ delete timers;
+ logger->log("Core", Log::NOTICE, "Timers module shut down");
+ }
+
if (mtd)
{
mtd->shutdown();
{
Log::getInstance()->log("PlayerRadio", Log::DEBUG, "RADIO OUTPUT STREAM FULL!!!");
// stream is full and cant take anymore
+ threadLock();
threadWaitForSignal();
+ threadUnlock();
Log::getInstance()->log("PlayerRadio", Log::DEBUG, "BACK FROM WAIT");
}
{
// Log::getInstance()->log("Player", Log::DEBUG, "DEMUXER FULL!!!");
// demuxer is full and cant take anymore
+ threadLock();
threadWaitForSignal();
+ threadUnlock();
// Log::getInstance()->log("Player", Log::DEBUG, "BACK FROM WAIT");
}
void Thread::threadWaitForSignal()
{
- pthread_mutex_lock(&threadCondMutex);
pthread_cond_wait(&threadCond, &threadCondMutex);
- pthread_mutex_unlock(&threadCondMutex);
}
void Thread::threadWaitForSignalTimed(struct timespec* ts)
{
- pthread_mutex_lock(&threadCondMutex);
pthread_cond_timedwait(&threadCond, &threadCondMutex, ts);
- pthread_mutex_unlock(&threadCondMutex);
}
void Thread::threadSetKillable()
\r
logger->log("Timers", Log::DEBUG, "Timers init start");\r
\r
- threadLock();\r
+ threadLock(); // lock here, the thread loop will unlock and wait\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 1");\r
if (!threadStart())\r
{\r
shutdown();\r
return 0;\r
}\r
- threadUnlock();\r
\r
logger->log("Timers", Log::DEBUG, "Timers init end");\r
\r
{\r
if (!initted) return 0;\r
\r
+ logger->log("Timers", Log::DEBUG, "Starting set timer 1");\r
+\r
Timer* t = new Timer();\r
t->client = client;\r
t->clientReference = clientReference;\r
t->requestedTime.tv_sec = requestedTime;\r
t->requestedTime.tv_nsec = 0;\r
\r
+logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 2");\r
threadLock();\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 2");\r
timerList.push_back(t);\r
+ resetThreadFlag = true;\r
+ threadSignalNoLock();\r
+logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 2");\r
threadUnlock();\r
- threadSignal();\r
\r
- logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference);\r
+ logger->log("Timers", Log::DEBUG, "1 Have set timer for %p ref %i", client, clientReference);\r
\r
return 1;\r
}\r
{\r
if (!initted) return 0;\r
\r
+ logger->log("Timers", Log::DEBUG, "Starting set timer 2");\r
+\r
Timer* t = new Timer();\r
t->client = client;\r
t->clientReference = clientReference;\r
logger->log("Timers", Log::DEBUG, "Second rollover - CHECK FIXME");\r
}\r
\r
+logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 3");\r
threadLock();\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 3");\r
timerList.push_back(t);\r
+ resetThreadFlag = true;\r
+ threadSignalNoLock();\r
+logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 3");\r
threadUnlock();\r
- threadSignal();\r
\r
- logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference);\r
+ logger->log("Timers", Log::DEBUG, "2 Have set timer for %p ref %i", client, clientReference);\r
\r
return 1;\r
}\r
{\r
if (!initted) return 0;\r
\r
+ logger->log("Timers", Log::DEBUG, "Starting cancel timer %p %i, list size = %i", client, clientReference, timerList.size());\r
+\r
+logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 4");\r
threadLock();\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 4");\r
TimerList::iterator i;\r
Timer* currentTimer = NULL;\r
for(i = timerList.begin(); i != timerList.end(); i++)\r
{\r
currentTimer = *i;\r
+ logger->log("Timers", Log::DEBUG, "I: %p %i : %p %i", client, clientReference, currentTimer->client, currentTimer->clientReference);\r
if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference))\r
{\r
timerList.erase(i);\r
+ logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);\r
break;\r
// At this point currentTimer is not in the list but might still be nextTimer in the thread\r
}\r
{\r
// no timer found\r
logger->log("Timers", Log::DEBUG, "No timer found in cancelTimer %p ref %i", client, clientReference);\r
+logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 4");\r
threadUnlock();\r
return 0;\r
}\r
\r
- // FIXME how to delete a cancelled timer?\r
- // Just delete it, thread now checks to see if timer is still valid when it wakes up\r
-\r
+ resetThreadFlag = true;\r
+ threadSignalNoLock();\r
+logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 4");\r
threadUnlock();\r
- threadSignal();\r
\r
- logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference);\r
\r
return 1;\r
}\r
}\r
}\r
}\r
+ }\r
\r
- if (nextTimer)\r
- {\r
- threadWaitForSignalTimed(&nextTime); // FIXME does this work if the time is in the past?\r
- logger->log("Timers", Log::DEBUG, "FIXME CHECK does waitforsignaltimed work for time < now?");\r
+ if (nextTimer)\r
+ {\r
+ logger->log("Timers", Log::DEBUG, "List size: %i. nextTimer: %p. nextTime.tv_sec: %li. nextTime.tv_nsec: %li", timerList.size(), nextTimer, nextTime.tv_sec, nextTime.tv_nsec);\r
\r
- // unlocks in the wait\r
- }\r
- else\r
- {\r
- threadWaitForSignal();\r
- // unlocks in the wait\r
- }\r
\r
- // ok. we have been signalled or the time has run out\r
- // This only gets signalled if it is to reset or die\r
+logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (1)");\r
+ threadWaitForSignalTimed(&nextTime); // FIXME does this work if the time is in the past?\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 5");\r
+ logger->log("Timers", Log::DEBUG, "FIXME CHECK does waitforsignaltimed work for time < now?");\r
\r
- // First check for die..\r
- threadCheckExit(); // exiting thread with mutex locked\r
+ // unlocks in the wait\r
+ }\r
+ else\r
+ {\r
+logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (2)");\r
+ threadWaitForSignal();\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 6");\r
+ // unlocks in the wait\r
+ }\r
\r
- // Check for reset..\r
- if (resetThreadFlag) continue;\r
+ // ok. we have been signalled or the time has run out\r
+ // This only gets signalled if it is to reset or die\r
\r
- // timer ran out\r
- // we have the lock, but we didn't in the wait. in case a timer was deleted during the wait,\r
- // check to see if object nextTimer is still in the list\r
- // FIXME - actually imlement the above\r
+ // First check for die..\r
+ threadCheckExit(); // exiting thread with mutex locked\r
\r
- // Ok. Get the main lock.\r
- // If we get the main lock, the view can't be deleted before the timer gets there.\r
- // (But will need to call Command->postMessageNoLock) to keep the lock\r
- // How to run message queue then?\r
- // Ah, no need to worry, if it is locked then main thread is waiting on getButtonPress and will\r
- // run the queue afterwards anyway\r
- // If we don't get the lock, lets say the view is deleted while we wait.\r
- // As part of its delete process, it will cancel its timer AND CAUSE DEADLOCK. DAMN.\r
+ // Check for reset..\r
+ // This can be caused by an addition or deletion to the list\r
+ if (resetThreadFlag) continue;\r
\r
+ // timer ran out\r
\r
- Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference);\r
+ Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference);\r
\r
- // send this timer to the timer receiver somehow\r
- // possibly give to command message queue\r
+ // send this timer to the timer receiver, via the command message queue\r
+ // so that the gui mutex is locked when it happens\r
\r
- Message* m = new Message();\r
- m->from = this;\r
- m->to = nextTimer->client;\r
- m->message = Message::TIMER;\r
- m->parameter = nextTimer->clientReference;\r
- Command::getInstance()->postMessage(m);\r
+ Message* m = new Message();\r
+ m->from = this;\r
+ m->to = nextTimer->client;\r
+ m->message = Message::TIMER;\r
+ m->parameter = nextTimer->clientReference;\r
\r
+ if (!Command::getInstance()->postMessageIfNotBusy(m))\r
+ {\r
+ // GUI mutex was locked\r
+ // abort this timer delivery - it might be trying to be deleted!\r
+ delete m;\r
+\r
+ // now unlock the timers mutex for a fraction of a second\r
+ // in case the gui thread is waiting on the timers mutex\r
+ threadUnlock();\r
+logger->log("Timers", Log::DEBUG, "un-LOCKED -TIMERS- MUTEX (3)");\r
+ printf("\n\n\n WOOOOO \n\n\n The anti deadlock code is working!!! \n\n\n");\r
+ usleep(10000); // 5ms - too long?\r
+logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 7");\r
+ threadLock();\r
+logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 7");\r
+ resetThreadFlag = true;\r
+ }\r
+ else\r
+ {\r
+ // timer was delivered\r
timerList.remove(nextTimer);\r
delete nextTimer;\r
nextTimer = NULL;\r
-\r
resetThreadFlag = true;\r
}\r
}\r
}\r
\r
-void Timers::threadPostStopCleanup()\r
-{\r
-}\r
+/*\r
+\r
+Avoiding deadlock using the timer class...\r
+\r
+Situation:\r
+\r
+timer condwait finishes\r
+timers is about to fire a timer\r
+timers locks timers-mutex\r
+\r
+ user presses a button\r
+ command locks gui-mutex\r
+\r
+timers tries to get gui-mutex\r
+\r
+ view receives button\r
+ view wants to delete itself\r
+ view tries to deletetimer\r
+ goes into delete timer\r
+ waits on timers mutex\r
+\r
+- deadlock\r
+\r
+\r
+Solution:\r
+\r
+timers tries to get gui mutex\r
+if mutex is locked already abort\r
+unlock timers mutex\r
+wait a fraction of time\r
+(allow other thread to lock timers mutex)\r
+lock timers mutex\r
+set reset flag to recalculate\r
+- if timer has been cancelled next timer will be calced\r
+- if timer has not been cancelled it will be called next\r
+\r
+*/\r
\r
// Thread stuff\r
virtual void threadMethod();\r
- virtual void threadPostStopCleanup();\r
+ virtual void threadPostStopCleanup() {};\r
\r
private:\r
static Timers* instance;\r
VVideoLive* v = new VVideoLive(chanList, chan->type);
v->channelChange(VVideoLive::NUMBER, chan->number);
- ViewMan::getInstance()->addNoLock(v);
+ ViewMan::getInstance()->add(v);
v->draw();
v->show();
vs->show();
viewman->add(vs); // FIXME - do this better - perhaps post message to Command
// Otherwise it will be using ViewMan without the Command mutex locked
+ threadLock();
threadWaitForSignal();
+ threadUnlock();
}
if (!irun)
/*\r
- Copyright 2004-2005 Brian Walton\r
+ Copyright 2005 Brian Walton\r
\r
This file is part of VOMP.\r
\r
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
*/\r
/*\r
- vepg presents a 2 dimensional electronic programme guide with channels down \r
+ vepg presents a 2 dimensional electronic programme guide with channels down\r
the y axis and time along the x axis.\r
- Programmes are layed on the x axis as alterate coloured blocks with as much \r
+ Programmes are layed on the x axis as alterate coloured blocks with as much\r
of the programme title as will fit inside the block shown as text.\r
- Up and down commands step through the channels whilst left and right commands \r
+ Up and down commands step through the channels whilst left and right commands\r
move through the programmes of the currently selected channel.\r
- When a programme is selected, it highlights in the grid and full programe details \r
+ When a programme is selected, it highlights in the grid and full programe details\r
(start time, title and description) are displayed in an area at te top left of the screen.\r
Any currently programmed timers will display in the grid and in the orogramme detail window as red\r
It is possible to select a programme to be recorded by pressing the record button.\r
The video stream currently being viewed is shown as quarter screen in the top right.\r
*/\r
- \r
+\r
#include "vepg.h"\r
\r
VEpg::VEpg(VVideoLive* v, UINT currentChannel)\r
// initialise array of pointers to eventlist structures\r
eventLista[listIndex] = NULL;\r
}\r
- \r
+\r
\r
// Create pallet on which to paint our epg view and position it in centre of screen.\r
// Need to reduce size to deal with overscanning TVs.\r
create(512, 384);\r
setScreenPos(64, 51);\r
}\r
- \r
+\r
// beautify\r
Colour transparent = Colour(0, 0, 0, 0);\r
setBackgroundColour(transparent);\r
int keyx = chanListbox.getOffsetX();\r
int keyy = chanListbox.getOffsetY() + chanListbox.getHeight() + 2;\r
surface->fillblt(keyx, keyy, 610, Surface::getFontHeight() * 2 + 14, surface->rgba(100, 100, 100, 255));\r
- \r
+\r
WSymbol w;\r
w.setSurface(surface);\r
- \r
+\r
w.nextSymbol = WSymbol::LEFTARROW;\r
w.setSurfaceOffset(keyx + 1, keyy + 20);\r
w.draw();\r
- \r
+\r
w.nextSymbol = WSymbol::UP;\r
w.setSurfaceOffset(keyx + 26, keyy + 3);\r
w.draw();\r
w.nextSymbol = WSymbol::DOWN;\r
w.setSurfaceOffset(keyx + 26, keyy + 36);\r
w.draw();\r
- \r
+\r
w.nextSymbol = WSymbol::RIGHTARROW;\r
w.setSurfaceOffset(keyx + 50, keyy + 20);\r
w.draw();\r
- \r
+\r
drawText("OK", keyx + 18, keyy + 20, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 72, keyy + 4, 104, Surface::getFontHeight() + 2, surface->rgba(200, 0, 0, 255));\r
drawText("Page up", keyx + 74, keyy + 5, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 72, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, surface->rgba(0, 200, 0, 255));\r
drawText("Page down", keyx + 74, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 180, keyy + 4, 104, Surface::getFontHeight() + 2, surface->rgba(200, 200, 0, 255));\r
drawText("-24 hours", keyx + 182, keyy + 5, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 180, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, surface->rgba( 0, 0, 200, 255));\r
drawText("+24 hours", keyx + 182, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 290, keyy + 4, 180, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
drawText("Guide / Back: Close", keyx + 292 , keyy + 5, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 290, keyy + Surface::getFontHeight() + 8, 180, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
Colour red = Colour(130, 0, 0);\r
drawText("Rec: Set timer", keyx + 292, keyy + Surface::getFontHeight() + 9, red);\r
- \r
+\r
surface->fillblt(keyx + 474, keyy + 4, 128, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
w.nextSymbol = WSymbol::PLAY;\r
w.setSurfaceOffset(keyx + 476, keyy + 5);\r
w.draw();\r
drawText("Sel channel", keyx + 496, keyy + 5, Colour::LIGHTTEXT);\r
- \r
+\r
surface->fillblt(keyx + 474, keyy + Surface::getFontHeight() + 8, 128, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255));\r
drawText("Go: Preview", keyx + 476, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT);\r
}\r
}\r
case Remote::DF_RIGHT:\r
case Remote::RIGHT:\r
- { \r
+ {\r
// cursor right through time\r
selTime = thisEvent.time + thisEvent.duration;\r
draw();\r
return 2;\r
}\r
case Remote::RED:\r
- { \r
+ {\r
// cursor up one page\r
chanListbox.pageUp();\r
draw();\r
return 2;\r
}\r
case Remote::GREEN:\r
- { \r
+ {\r
// cursor down one page\r
chanListbox.pageDown();\r
draw();\r
return 2;\r
}\r
case Remote::BLUE:\r
- { \r
+ {\r
// step forward 24 hours\r
selTime += 24 * 60 * 60;\r
draw();\r
return 2;\r
}\r
case Remote::YELLOW:\r
- { \r
+ {\r
// step forward 24 hours\r
selTime -= 24 * 60 * 60;\r
draw();\r
surface->fillblt(515, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 255, 255, 255));\r
// pointer to selTime\r
surface->fillblt(155 + (selTime - ltime) / 20, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 50, 50, 255));\r
- \r
+\r
// TODO should the above two comditional statements be combined to avoid calling updateEventList() twice?\r
Event* event;\r
Event noevent; // an event to use if there are gaps in the epg\r
sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter());\r
for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel\r
{\r
- fg = Colour::LIGHTTEXT;\r
+ fg = Colour::LIGHTTEXT;\r
event = (*eventLista[listIndex])[e];\r
- if (event)\r
- {\r
- UINT end = event->time + event->duration; // programme end time\r
- if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window\r
- continue; // that's enough of this channel's events\r
- if(end <= UINT(ltime)) // programme ends before LHS of window\r
- continue; // this event is before the window - let's try the next event\r
- // this event is one we are interested in\r
- bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour\r
- swapColour = !swapColour; // it wil be the other colour next time\r
- if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)\r
- {\r
- // this is the selected programme\r
- thisEvent.setdescription(event->description);\r
- thisEvent.duration = event->duration;\r
- thisEvent.time = event->time;\r
- thisEvent.settitle(event->title);\r
- thisEvent.id = event->id;\r
- if(thisEvent.id == 0)\r
- thisEvent.id = 1;\r
- bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
- fg = Colour::DARKTEXT;\r
- }\r
- else\r
- {\r
- if (currentRow && thisEvent.id == 0)\r
- {\r
- if (end <= UINT(selTime) && end > UINT(thisEvent.time))\r
- thisEvent.time = end;\r
- if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)\r
- thisEvent.duration = event->time - thisEvent.time;\r
- } \r
- }\r
- paintCell(event, y, bg, fg);\r
- }\r
+ if (event)\r
+ {\r
+ UINT end = event->time + event->duration; // programme end time\r
+ if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window\r
+ continue; // that's enough of this channel's events\r
+ if(end <= UINT(ltime)) // programme ends before LHS of window\r
+ continue; // this event is before the window - let's try the next event\r
+ // this event is one we are interested in\r
+ bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour\r
+ swapColour = !swapColour; // it wil be the other colour next time\r
+ if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow)\r
+ {\r
+ // this is the selected programme\r
+ thisEvent.setdescription(event->description);\r
+ thisEvent.duration = event->duration;\r
+ thisEvent.time = event->time;\r
+ thisEvent.settitle(event->title);\r
+ thisEvent.id = event->id;\r
+ if(thisEvent.id == 0)\r
+ thisEvent.id = 1;\r
+ bg = Colour::SELECTHIGHLIGHT; // highlight cell\r
+ fg = Colour::DARKTEXT;\r
+ }\r
+ else\r
+ {\r
+ if (currentRow && thisEvent.id == 0)\r
+ {\r
+ if (end <= UINT(selTime) && end > UINT(thisEvent.time))\r
+ thisEvent.time = end;\r
+ if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration)\r
+ thisEvent.duration = event->time - thisEvent.time;\r
+ }\r
+ }\r
+ paintCell(event, y, bg, fg);\r
+ }\r
}\r
}\r
else\r
else\r
{\r
bg = Colour::NOPROGRAMME;\r
- fg = Colour::LIGHTTEXT;\r
+ fg = Colour::LIGHTTEXT;\r
noevent.settitle("No programme details");\r
- paintCell(&noevent, y, bg, fg);\r
+ paintCell(&noevent, y, bg, fg);\r
}\r
}\r
y += Surface::getFontHeight() + 1;\r
setInfo(&thisEvent);\r
}\r
\r
-void VEpg::updateEventList() \r
+void VEpg::updateEventList()\r
{\r
Channel* chan;\r
for(UINT listIndex = 0; listIndex < 7; listIndex++)\r
surface->drawText(tT, x+2, y, fg.red, fg.green, fg.blue);\r
}\r
delete tT;\r
- \r
+\r
}\r
\r
time_t VEpg::prevHour(time_t* t)\r
/*\r
- Copyright 2004-2005 Chris Tallon\r
+ Copyright 2005 Brian Walton\r
\r
This file is part of VOMP.\r
\r
private:\r
void setInfo(Event* event); // display details of selected programme\r
void drawgrid(); // redraws grid and select programme\r
- \r
+\r
WSelectList chanListbox; // listbox to display available channels\r
WTextbox progTitle; // area to display time and title of selected programme\r
WTextbox progInfo; // area to display details of selected programme\r
EventList* eventList; // list of events (programmes) for a channel\r
Event thisEvent; // the selected event\r
- time_t selTime; // current selection time \r
+ time_t selTime; // current selection time\r
UINT e; // temp used to point to an event\r
ChannelList* chanList; // list of available channels\r
tm* epgtime; // selected time within epg\r
else if (retVal == 4)
{
Log::getInstance()->log("ViewMan", Log::DEBUG, "Return 4: i=%i, views[i]=%p", i, views[i]);
- removeView(views[i], 1);
+ removeView(views[i]);
retVal2 = 1;
break;
}
{
case Message::CLOSE_ME:
{
- removeView((View*)m->from, 1);
+ removeView((View*)m->from);
break;
}
case Message::ADD_VIEW:
#include <stdio.h>
#include <time.h>
#include <signal.h>
-#include <ext/slist>
+
+// might need <ext/slist> for newer compilers?
+#include <slist>
#include "defines.h"
#include "view.h"
#include "region.h"
//using namespace std;
-using namespace __gnu_cxx;
+
+//using namespace __gnu_cxx; // needed for newer compilers?
typedef slist<Region> RegionList;
int shutdown();
int add(View* v);
- int removeView(View* toRemove = NULL);
+ int removeView(View* toRemove);
void removeAll();
int handleCommand(UCHAR command);
sl.setNoLoop();
setChannel(channel);
-
- // set a timer for deleting view
- Timers::getInstance()->setTimer(this, 1, (struct timespec){4, 0});
}
VLiveBanner::~VLiveBanner()
case Remote::OK:
case Remote::BACK:
{
+ Timers::getInstance()->cancelTimer(this, 1); // if it exists
return 4;
}
case Remote::DF_UP:
}
case Remote::CHANNELUP:
{
- ViewMan::getInstance()->timedDelete(this, 0, 0); // cancel timer so this view is still here later
+ // cancel timer so this view is still here later
+ Timers::getInstance()->cancelTimer(this, 1); // if it exists
Message* m = new Message();
m->from = this;
}
case Remote::CHANNELDOWN:
{
- ViewMan::getInstance()->timedDelete(this, 0, 0);
+ // cancel timer so this view is still here later
+ Timers::getInstance()->cancelTimer(this, 1); // if it exists
Message* m = new Message();
m->from = this;
}
vi->create(510, 270);
- ViewMan::getInstance()->addNoLock(vi);
+ ViewMan::getInstance()->add(vi);
vi->draw();
vi->show();
if (toPlay)
{
VVideoRec* vidrec = new VVideoRec(toPlay);
- ViewMan::getInstance()->addNoLock(vidrec);
+ ViewMan::getInstance()->add(vidrec);
vidrec->draw();
vidrec->show();
vidrec->go(0);
ULLONG position = VDR::getInstance()->getResumePoint(toResume->fileName);
VVideoRec* vidrec = new VVideoRec(toResume);
- ViewMan::getInstance()->addNoLock(vidrec);
+ ViewMan::getInstance()->add(vidrec);
vidrec->draw();
vidrec->show();
vidrec->go(position);
{
VRecordingList* sub = new VRecordingList(this);
sub->setDir(curDir);
- ViewMan::getInstance()->addNoLock(sub);
+ ViewMan::getInstance()->add(sub);
sub->draw();
sub->show();
VRecordingMenu* v = new VRecordingMenu();
v->setParent(this);
v->setRecording(current);
- ViewMan::getInstance()->addNoLock(v);
+ ViewMan::getInstance()->add(v);
v->draw();
v->show();
return 2;
}
vi->create(490, 300);
- ViewMan::getInstance()->addNoLock(vi);
+ ViewMan::getInstance()->add(vi);
vi->draw();
vi->show();
v->setScreenPos(220, 140);
}
- ViewMan::getInstance()->addNoLock(v);
+ ViewMan::getInstance()->add(v);
v->draw();
v->show();
return 2;
case Remote::ZERO ... Remote::NINE:
{
VChannelSelect* v = new VChannelSelect(this, command);
- viewman->addNoLock(v);
+ viewman->add(v);
v->draw();
v->show();
}
else
{
unavailable = 0;
- ViewMan::getInstance()->removeView(unavailableView, 1);
+ ViewMan::getInstance()->removeView(unavailableView);
unavailableView = NULL;
}
}
printf("1\n");
if (unavailable) return;
printf("2\n");
- if (!noRemoveVLB) viewman->removeView(vlb, 1); // if live banner is present, remove it. won't cause damage if its not present
+ if (!noRemoveVLB) viewman->removeView(vlb); // if live banner is present, remove it. won't cause damage if its not present
printf("3\n");
player->stop();
{
if (unavailable) showUnavailable(0);
vepg = new VEpg(this, currentChannel);
- ViewMan::getInstance()->addNoLock(vepg);
+ ViewMan::getInstance()->add(vepg);
Video::getInstance()->setMode(Video::QUARTER);
Video::getInstance()->setPosition(170, 5); //TODO need to deal with 4:3 switching
vepg->draw();
VChannelList* vchan = new VChannelList(VDR::VIDEO);
vchan->setList(chanList);
- ViewMan::getInstance()->addNoLock(vchan);
+ ViewMan::getInstance()->add(vchan);
vchan->draw();
vchan->show();
VChannelList* vchan = new VChannelList(VDR::RADIO);
vchan->setList(chanList);
- ViewMan::getInstance()->addNoLock(vchan);
+ ViewMan::getInstance()->add(vchan);
vchan->draw();
vchan->show();
}
viewWait->setOneLiner(tr("Downloading recordings list"));
viewWait->draw();
viewWait->show();
- viewman->addNoLock(viewWait);
+ viewman->add(viewWait);
VDR* vdr = VDR::getInstance();
VRecordingList* vrec = new VRecordingList(NULL);
vrec->setDir(recDir);
- ViewMan::getInstance()->addNoLock(vrec);
+ ViewMan::getInstance()->add(vrec);
vrec->draw();
vrec->show();
}
Log::getInstance()->log("VWelcome", Log::DEBUG, "possible delay start");
- viewman->removeView(viewWait, 1);
+ viewman->removeView(viewWait);
Log::getInstance()->log("VWelcome", Log::DEBUG, "possible delay end");
}
void VWelcome::doOptions()
{
VOptions* voptions = new VOptions();
- ViewMan::getInstance()->addNoLock(voptions);
+ ViewMan::getInstance()->add(voptions);
voptions->draw();
voptions->show();
}
/*\r
- Copyright 2004-2005 Chris Tallon\r
+ Copyright 2005 Brian Walton\r
\r
This file is part of VOMP.\r
\r
/*\r
- Copyright 2004-2005 Chris Tallon\r
+ Copyright 2005 Brian Walton\r
\r
This file is part of VOMP.\r
\r