From 24a6a756a57bb0ae38bcb9b8aa793b71efc5fd9a Mon Sep 17 00:00:00 2001 From: Chris Tallon Date: Fri, 2 Dec 2005 23:10:42 +0000 Subject: [PATCH] New timers code --- command.cc | 33 ++++++++- command.h | 1 + main.cc | 21 ++++++ playerradio.cc | 2 + playervideo.cc | 2 + thread.cc | 4 -- timers.cc | 171 ++++++++++++++++++++++++++++++++-------------- timers.h | 2 +- vchannellist.cc | 2 +- vconnect.cc | 2 + vepg.cc | 134 ++++++++++++++++++------------------ vepg.h | 6 +- viewman.cc | 4 +- viewman.h | 9 ++- vlivebanner.cc | 12 ++-- vrecordinglist.cc | 8 +-- vrecordingmenu.cc | 4 +- vvideolive.cc | 8 +-- vwelcome.cc | 12 ++-- wtextbox.cc | 2 +- wtextbox.h | 2 +- 21 files changed, 282 insertions(+), 159 deletions(-) diff --git a/command.cc b/command.cc index ef48348..abf770b 100644 --- a/command.cc +++ b/command.cc @@ -131,11 +131,13 @@ void Command::run() { // 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; @@ -154,9 +156,32 @@ void Command::postMessage(Message* m) // 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) @@ -205,6 +230,12 @@ 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! @@ -294,7 +325,7 @@ void Command::doJustConnected(VConnect* vconnect) { I18n::initialize(); Video* video = Video::getInstance(); - viewman->removeView(vconnect, 0); + viewman->removeView(vconnect); VInfo* vi = new VInfo(); vi->create(400, 200); diff --git a/command.h b/command.h index 91526f0..ccd651f 100644 --- a/command.h +++ b/command.h @@ -68,6 +68,7 @@ class Command : public MessageQueue 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); diff --git a/main.cc b/main.cc index a4e1bfe..4dfbbc2 100644 --- a/main.cc +++ b/main.cc @@ -30,6 +30,7 @@ #include "remote.h" #include "led.h" #include "mtd.h" +#include "timers.h" #include "video.h" #include "audio.h" #include "vdr.h" @@ -47,6 +48,7 @@ Remote* remote; Mtd* mtd; Led* led; Osd* osd; +Timers* timers; ViewMan* viewman; Command* command; VDR* vdr; @@ -64,6 +66,7 @@ int main(int argc, char** argv) remote = new Remote(); mtd = new Mtd(); led = new Led(); + timers = new Timers(); osd = new Osd(); vdr = new VDR(); video = new Video(); @@ -188,6 +191,17 @@ int main(int argc, char** argv) 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"); @@ -322,6 +336,13 @@ void shutdown(int code) 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(); diff --git a/playerradio.cc b/playerradio.cc index ec41b2b..419391e 100644 --- a/playerradio.cc +++ b/playerradio.cc @@ -368,7 +368,9 @@ void PlayerRadio::threadMethod() { 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"); } diff --git a/playervideo.cc b/playervideo.cc index 82ff847..0a326e8 100644 --- a/playervideo.cc +++ b/playervideo.cc @@ -608,7 +608,9 @@ void PlayerVideo::threadMethod() { // 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"); } diff --git a/thread.cc b/thread.cc index d8bb647..6e210a5 100644 --- a/thread.cc +++ b/thread.cc @@ -98,16 +98,12 @@ void Thread::threadSignalNoLock() 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() diff --git a/timers.cc b/timers.cc index eea0f89..e734f5b 100755 --- a/timers.cc +++ b/timers.cc @@ -47,13 +47,13 @@ int Timers::init() logger->log("Timers", Log::DEBUG, "Timers init start"); - threadLock(); + threadLock(); // lock here, the thread loop will unlock and wait +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 1"); if (!threadStart()) { shutdown(); return 0; } - threadUnlock(); logger->log("Timers", Log::DEBUG, "Timers init end"); @@ -88,18 +88,24 @@ int Timers::setTimer(TimerReceiver* client, int clientReference, time_t requeste { if (!initted) return 0; + logger->log("Timers", Log::DEBUG, "Starting set timer 1"); + Timer* t = new Timer(); t->client = client; t->clientReference = clientReference; t->requestedTime.tv_sec = requestedTime; t->requestedTime.tv_nsec = 0; +logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 2"); threadLock(); +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 2"); timerList.push_back(t); + resetThreadFlag = true; + threadSignalNoLock(); +logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 2"); threadUnlock(); - threadSignal(); - logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference); + logger->log("Timers", Log::DEBUG, "1 Have set timer for %p ref %i", client, clientReference); return 1; } @@ -108,6 +114,8 @@ int Timers::setTimer(TimerReceiver* client, int clientReference, struct timespec { if (!initted) return 0; + logger->log("Timers", Log::DEBUG, "Starting set timer 2"); + Timer* t = new Timer(); t->client = client; t->clientReference = clientReference; @@ -124,12 +132,16 @@ int Timers::setTimer(TimerReceiver* client, int clientReference, struct timespec logger->log("Timers", Log::DEBUG, "Second rollover - CHECK FIXME"); } +logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 3"); threadLock(); +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 3"); timerList.push_back(t); + resetThreadFlag = true; + threadSignalNoLock(); +logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 3"); threadUnlock(); - threadSignal(); - logger->log("Timers", Log::DEBUG, "Have set timer for %p ref %i", client, clientReference); + logger->log("Timers", Log::DEBUG, "2 Have set timer for %p ref %i", client, clientReference); return 1; } @@ -138,15 +150,21 @@ int Timers::cancelTimer(TimerReceiver* client, int clientReference) { if (!initted) return 0; + logger->log("Timers", Log::DEBUG, "Starting cancel timer %p %i, list size = %i", client, clientReference, timerList.size()); + +logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 4"); threadLock(); +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 4"); TimerList::iterator i; Timer* currentTimer = NULL; for(i = timerList.begin(); i != timerList.end(); i++) { currentTimer = *i; + logger->log("Timers", Log::DEBUG, "I: %p %i : %p %i", client, clientReference, currentTimer->client, currentTimer->clientReference); if ((currentTimer->client == client) && (currentTimer->clientReference == clientReference)) { timerList.erase(i); + logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference); break; // At this point currentTimer is not in the list but might still be nextTimer in the thread } @@ -155,17 +173,16 @@ int Timers::cancelTimer(TimerReceiver* client, int clientReference) { // no timer found logger->log("Timers", Log::DEBUG, "No timer found in cancelTimer %p ref %i", client, clientReference); +logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 4"); threadUnlock(); return 0; } - // FIXME how to delete a cancelled timer? - // Just delete it, thread now checks to see if timer is still valid when it wakes up - + resetThreadFlag = true; + threadSignalNoLock(); +logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX 4"); threadUnlock(); - threadSignal(); - logger->log("Timers", Log::DEBUG, "Removed timer for %p ref %i", client, clientReference); return 1; } @@ -220,65 +237,113 @@ void Timers::threadMethod() } } } + } - if (nextTimer) - { - threadWaitForSignalTimed(&nextTime); // FIXME does this work if the time is in the past? - logger->log("Timers", Log::DEBUG, "FIXME CHECK does waitforsignaltimed work for time < now?"); + if (nextTimer) + { + 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); - // unlocks in the wait - } - else - { - threadWaitForSignal(); - // unlocks in the wait - } - // ok. we have been signalled or the time has run out - // This only gets signalled if it is to reset or die +logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (1)"); + threadWaitForSignalTimed(&nextTime); // FIXME does this work if the time is in the past? +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 5"); + logger->log("Timers", Log::DEBUG, "FIXME CHECK does waitforsignaltimed work for time < now?"); - // First check for die.. - threadCheckExit(); // exiting thread with mutex locked + // unlocks in the wait + } + else + { +logger->log("Timers", Log::DEBUG, "about to un-LOCK -TIMERS- MUTEX (2)"); + threadWaitForSignal(); +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 6"); + // unlocks in the wait + } - // Check for reset.. - if (resetThreadFlag) continue; + // ok. we have been signalled or the time has run out + // This only gets signalled if it is to reset or die - // timer ran out - // we have the lock, but we didn't in the wait. in case a timer was deleted during the wait, - // check to see if object nextTimer is still in the list - // FIXME - actually imlement the above + // First check for die.. + threadCheckExit(); // exiting thread with mutex locked - // Ok. Get the main lock. - // If we get the main lock, the view can't be deleted before the timer gets there. - // (But will need to call Command->postMessageNoLock) to keep the lock - // How to run message queue then? - // Ah, no need to worry, if it is locked then main thread is waiting on getButtonPress and will - // run the queue afterwards anyway - // If we don't get the lock, lets say the view is deleted while we wait. - // As part of its delete process, it will cancel its timer AND CAUSE DEADLOCK. DAMN. + // Check for reset.. + // This can be caused by an addition or deletion to the list + if (resetThreadFlag) continue; + // timer ran out - Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference); + Log::getInstance()->log("Timers", Log::DEBUG, "Timer firing for client %p ref %i", nextTimer->client, nextTimer->clientReference); - // send this timer to the timer receiver somehow - // possibly give to command message queue + // send this timer to the timer receiver, via the command message queue + // so that the gui mutex is locked when it happens - Message* m = new Message(); - m->from = this; - m->to = nextTimer->client; - m->message = Message::TIMER; - m->parameter = nextTimer->clientReference; - Command::getInstance()->postMessage(m); + Message* m = new Message(); + m->from = this; + m->to = nextTimer->client; + m->message = Message::TIMER; + m->parameter = nextTimer->clientReference; + if (!Command::getInstance()->postMessageIfNotBusy(m)) + { + // GUI mutex was locked + // abort this timer delivery - it might be trying to be deleted! + delete m; + + // now unlock the timers mutex for a fraction of a second + // in case the gui thread is waiting on the timers mutex + threadUnlock(); +logger->log("Timers", Log::DEBUG, "un-LOCKED -TIMERS- MUTEX (3)"); + printf("\n\n\n WOOOOO \n\n\n The anti deadlock code is working!!! \n\n\n"); + usleep(10000); // 5ms - too long? +logger->log("Timers", Log::DEBUG, "Waiting for LOCK -TIMERS- MUTEX 7"); + threadLock(); +logger->log("Timers", Log::DEBUG, "LOCKED -TIMERS- MUTEX 7"); + resetThreadFlag = true; + } + else + { + // timer was delivered timerList.remove(nextTimer); delete nextTimer; nextTimer = NULL; - resetThreadFlag = true; } } } -void Timers::threadPostStopCleanup() -{ -} +/* + +Avoiding deadlock using the timer class... + +Situation: + +timer condwait finishes +timers is about to fire a timer +timers locks timers-mutex + + user presses a button + command locks gui-mutex + +timers tries to get gui-mutex + + view receives button + view wants to delete itself + view tries to deletetimer + goes into delete timer + waits on timers mutex + +- deadlock + + +Solution: + +timers tries to get gui mutex +if mutex is locked already abort +unlock timers mutex +wait a fraction of time +(allow other thread to lock timers mutex) +lock timers mutex +set reset flag to recalculate +- if timer has been cancelled next timer will be calced +- if timer has not been cancelled it will be called next + +*/ diff --git a/timers.h b/timers.h index 4881e3a..3a88b06 100755 --- a/timers.h +++ b/timers.h @@ -61,7 +61,7 @@ class Timers : public Thread // Thread stuff virtual void threadMethod(); - virtual void threadPostStopCleanup(); + virtual void threadPostStopCleanup() {}; private: static Timers* instance; diff --git a/vchannellist.cc b/vchannellist.cc index 83ae18b..69d2ce0 100644 --- a/vchannellist.cc +++ b/vchannellist.cc @@ -203,7 +203,7 @@ int VChannelList::handleCommand(int command) 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(); diff --git a/vconnect.cc b/vconnect.cc index b487110..dbcbb4b 100644 --- a/vconnect.cc +++ b/vconnect.cc @@ -97,7 +97,9 @@ void VConnect::threadMethod() 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) diff --git a/vepg.cc b/vepg.cc index 4bb9fa7..190a401 100644 --- a/vepg.cc +++ b/vepg.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Brian Walton + Copyright 2005 Brian Walton This file is part of VOMP. @@ -18,19 +18,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* - vepg presents a 2 dimensional electronic programme guide with channels down + vepg presents a 2 dimensional electronic programme guide with channels down the y axis and time along the x axis. - Programmes are layed on the x axis as alterate coloured blocks with as much + Programmes are layed on the x axis as alterate coloured blocks with as much of the programme title as will fit inside the block shown as text. - Up and down commands step through the channels whilst left and right commands + Up and down commands step through the channels whilst left and right commands move through the programmes of the currently selected channel. - When a programme is selected, it highlights in the grid and full programe details + When a programme is selected, it highlights in the grid and full programe details (start time, title and description) are displayed in an area at te top left of the screen. Any currently programmed timers will display in the grid and in the orogramme detail window as red It is possible to select a programme to be recorded by pressing the record button. The video stream currently being viewed is shown as quarter screen in the top right. */ - + #include "vepg.h" VEpg::VEpg(VVideoLive* v, UINT currentChannel) @@ -40,7 +40,7 @@ VEpg::VEpg(VVideoLive* v, UINT currentChannel) // initialise array of pointers to eventlist structures eventLista[listIndex] = NULL; } - + // Create pallet on which to paint our epg view and position it in centre of screen. // Need to reduce size to deal with overscanning TVs. @@ -58,7 +58,7 @@ VEpg::VEpg(VVideoLive* v, UINT currentChannel) create(512, 384); setScreenPos(64, 51); } - + // beautify Colour transparent = Colour(0, 0, 0, 0); setBackgroundColour(transparent); @@ -155,14 +155,14 @@ void VEpg::draw() int keyx = chanListbox.getOffsetX(); int keyy = chanListbox.getOffsetY() + chanListbox.getHeight() + 2; surface->fillblt(keyx, keyy, 610, Surface::getFontHeight() * 2 + 14, surface->rgba(100, 100, 100, 255)); - + WSymbol w; w.setSurface(surface); - + w.nextSymbol = WSymbol::LEFTARROW; w.setSurfaceOffset(keyx + 1, keyy + 20); w.draw(); - + w.nextSymbol = WSymbol::UP; w.setSurfaceOffset(keyx + 26, keyy + 3); w.draw(); @@ -170,38 +170,38 @@ void VEpg::draw() w.nextSymbol = WSymbol::DOWN; w.setSurfaceOffset(keyx + 26, keyy + 36); w.draw(); - + w.nextSymbol = WSymbol::RIGHTARROW; w.setSurfaceOffset(keyx + 50, keyy + 20); w.draw(); - + drawText("OK", keyx + 18, keyy + 20, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 72, keyy + 4, 104, Surface::getFontHeight() + 2, surface->rgba(200, 0, 0, 255)); drawText("Page up", keyx + 74, keyy + 5, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 72, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, surface->rgba(0, 200, 0, 255)); drawText("Page down", keyx + 74, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 180, keyy + 4, 104, Surface::getFontHeight() + 2, surface->rgba(200, 200, 0, 255)); drawText("-24 hours", keyx + 182, keyy + 5, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 180, keyy + Surface::getFontHeight() + 8, 104, Surface::getFontHeight() + 2, surface->rgba( 0, 0, 200, 255)); drawText("+24 hours", keyx + 182, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 290, keyy + 4, 180, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255)); drawText("Guide / Back: Close", keyx + 292 , keyy + 5, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 290, keyy + Surface::getFontHeight() + 8, 180, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255)); Colour red = Colour(130, 0, 0); drawText("Rec: Set timer", keyx + 292, keyy + Surface::getFontHeight() + 9, red); - + surface->fillblt(keyx + 474, keyy + 4, 128, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255)); w.nextSymbol = WSymbol::PLAY; w.setSurfaceOffset(keyx + 476, keyy + 5); w.draw(); drawText("Sel channel", keyx + 496, keyy + 5, Colour::LIGHTTEXT); - + surface->fillblt(keyx + 474, keyy + Surface::getFontHeight() + 8, 128, Surface::getFontHeight() + 2, surface->rgba( 180, 180, 180, 255)); drawText("Go: Preview", keyx + 476, keyy + Surface::getFontHeight() + 9, Colour::LIGHTTEXT); } @@ -236,7 +236,7 @@ int VEpg::handleCommand(int command) } case Remote::DF_RIGHT: case Remote::RIGHT: - { + { // cursor right through time selTime = thisEvent.time + thisEvent.duration; draw(); @@ -244,7 +244,7 @@ int VEpg::handleCommand(int command) return 2; } case Remote::RED: - { + { // cursor up one page chanListbox.pageUp(); draw(); @@ -252,7 +252,7 @@ int VEpg::handleCommand(int command) return 2; } case Remote::GREEN: - { + { // cursor down one page chanListbox.pageDown(); draw(); @@ -260,7 +260,7 @@ int VEpg::handleCommand(int command) return 2; } case Remote::BLUE: - { + { // step forward 24 hours selTime += 24 * 60 * 60; draw(); @@ -268,7 +268,7 @@ int VEpg::handleCommand(int command) return 2; } case Remote::YELLOW: - { + { // step forward 24 hours selTime -= 24 * 60 * 60; draw(); @@ -370,7 +370,7 @@ void VEpg::drawgrid() // redraws grid and select programme surface->fillblt(515, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 255, 255, 255)); // pointer to selTime surface->fillblt(155 + (selTime - ltime) / 20, timey + Surface::getFontHeight(), 2, 7, surface->rgba(255, 50, 50, 255)); - + // TODO should the above two comditional statements be combined to avoid calling updateEventList() twice? Event* event; Event noevent; // an event to use if there are gaps in the epg @@ -406,43 +406,43 @@ void VEpg::drawgrid() // redraws grid and select programme sort(eventLista[listIndex]->begin(), eventLista[listIndex]->end(), EventSorter()); for(e = 0; e < (eventLista[listIndex])->size(); e++) // step through events for this channel { - fg = Colour::LIGHTTEXT; + fg = Colour::LIGHTTEXT; event = (*eventLista[listIndex])[e]; - if (event) - { - UINT end = event->time + event->duration; // programme end time - if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window - continue; // that's enough of this channel's events - if(end <= UINT(ltime)) // programme ends before LHS of window - continue; // this event is before the window - let's try the next event - // this event is one we are interested in - bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour - swapColour = !swapColour; // it wil be the other colour next time - if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow) - { - // this is the selected programme - thisEvent.setdescription(event->description); - thisEvent.duration = event->duration; - thisEvent.time = event->time; - thisEvent.settitle(event->title); - thisEvent.id = event->id; - if(thisEvent.id == 0) - thisEvent.id = 1; - bg = Colour::SELECTHIGHLIGHT; // highlight cell - fg = Colour::DARKTEXT; - } - else - { - if (currentRow && thisEvent.id == 0) - { - if (end <= UINT(selTime) && end > UINT(thisEvent.time)) - thisEvent.time = end; - if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration) - thisEvent.duration = event->time - thisEvent.time; - } - } - paintCell(event, y, bg, fg); - } + if (event) + { + UINT end = event->time + event->duration; // programme end time + if(event->time >= UINT(ltime) + (WINDOW_WIDTH * 60)) // programme starts after RHS of window + continue; // that's enough of this channel's events + if(end <= UINT(ltime)) // programme ends before LHS of window + continue; // this event is before the window - let's try the next event + // this event is one we are interested in + bg = (swapColour)?Colour::PROGRAMMEA:Colour::PROGRAMMEB; // alternate cell colour + swapColour = !swapColour; // it wil be the other colour next time + if(event->time <= UINT(selTime) && end > UINT(selTime) && currentRow) + { + // this is the selected programme + thisEvent.setdescription(event->description); + thisEvent.duration = event->duration; + thisEvent.time = event->time; + thisEvent.settitle(event->title); + thisEvent.id = event->id; + if(thisEvent.id == 0) + thisEvent.id = 1; + bg = Colour::SELECTHIGHLIGHT; // highlight cell + fg = Colour::DARKTEXT; + } + else + { + if (currentRow && thisEvent.id == 0) + { + if (end <= UINT(selTime) && end > UINT(thisEvent.time)) + thisEvent.time = end; + if (event->time > UINT(selTime) && event->time < thisEvent.time + thisEvent.duration) + thisEvent.duration = event->time - thisEvent.time; + } + } + paintCell(event, y, bg, fg); + } } } else @@ -457,9 +457,9 @@ void VEpg::drawgrid() // redraws grid and select programme else { bg = Colour::NOPROGRAMME; - fg = Colour::LIGHTTEXT; + fg = Colour::LIGHTTEXT; noevent.settitle("No programme details"); - paintCell(&noevent, y, bg, fg); + paintCell(&noevent, y, bg, fg); } } y += Surface::getFontHeight() + 1; @@ -467,7 +467,7 @@ void VEpg::drawgrid() // redraws grid and select programme setInfo(&thisEvent); } -void VEpg::updateEventList() +void VEpg::updateEventList() { Channel* chan; for(UINT listIndex = 0; listIndex < 7; listIndex++) @@ -536,7 +536,7 @@ void VEpg::paintCell(Event* event, int yOffset, Colour bg, Colour fg) surface->drawText(tT, x+2, y, fg.red, fg.green, fg.blue); } delete tT; - + } time_t VEpg::prevHour(time_t* t) diff --git a/vepg.h b/vepg.h index b4e5a0b..d017015 100644 --- a/vepg.h +++ b/vepg.h @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2005 Brian Walton This file is part of VOMP. @@ -55,13 +55,13 @@ class VEpg : public View private: void setInfo(Event* event); // display details of selected programme void drawgrid(); // redraws grid and select programme - + WSelectList chanListbox; // listbox to display available channels WTextbox progTitle; // area to display time and title of selected programme WTextbox progInfo; // area to display details of selected programme EventList* eventList; // list of events (programmes) for a channel Event thisEvent; // the selected event - time_t selTime; // current selection time + time_t selTime; // current selection time UINT e; // temp used to point to an event ChannelList* chanList; // list of available channels tm* epgtime; // selected time within epg diff --git a/viewman.cc b/viewman.cc index c3ccbc8..633a574 100644 --- a/viewman.cc +++ b/viewman.cc @@ -363,7 +363,7 @@ int ViewMan::handleCommand(UCHAR command) 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; } @@ -404,7 +404,7 @@ void ViewMan::processMessage(Message* m) { case Message::CLOSE_ME: { - removeView((View*)m->from, 1); + removeView((View*)m->from); break; } case Message::ADD_VIEW: diff --git a/viewman.h b/viewman.h index 859dbce..fcef281 100644 --- a/viewman.h +++ b/viewman.h @@ -24,7 +24,9 @@ #include #include #include -#include + +// might need for newer compilers? +#include #include "defines.h" #include "view.h" @@ -35,7 +37,8 @@ #include "region.h" //using namespace std; -using namespace __gnu_cxx; + +//using namespace __gnu_cxx; // needed for newer compilers? typedef slist RegionList; @@ -50,7 +53,7 @@ class ViewMan : public MessageQueue int shutdown(); int add(View* v); - int removeView(View* toRemove = NULL); + int removeView(View* toRemove); void removeAll(); int handleCommand(UCHAR command); diff --git a/vlivebanner.cc b/vlivebanner.cc index 2b85d46..539b2ad 100644 --- a/vlivebanner.cc +++ b/vlivebanner.cc @@ -47,9 +47,6 @@ VLiveBanner::VLiveBanner(View* tparent, Channel* channel, bool bannerTakesComman sl.setNoLoop(); setChannel(channel); - - // set a timer for deleting view - Timers::getInstance()->setTimer(this, 1, (struct timespec){4, 0}); } VLiveBanner::~VLiveBanner() @@ -133,6 +130,7 @@ int VLiveBanner::handleCommand(int command) case Remote::OK: case Remote::BACK: { + Timers::getInstance()->cancelTimer(this, 1); // if it exists return 4; } case Remote::DF_UP: @@ -161,7 +159,8 @@ int VLiveBanner::handleCommand(int command) } 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; @@ -172,7 +171,8 @@ int VLiveBanner::handleCommand(int command) } 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; @@ -212,7 +212,7 @@ int VLiveBanner::handleCommand(int command) } vi->create(510, 270); - ViewMan::getInstance()->addNoLock(vi); + ViewMan::getInstance()->add(vi); vi->draw(); vi->show(); diff --git a/vrecordinglist.cc b/vrecordinglist.cc index c7f2b7b..8b5ba14 100644 --- a/vrecordinglist.cc +++ b/vrecordinglist.cc @@ -292,7 +292,7 @@ int VRecordingList::doPlay() if (toPlay) { VVideoRec* vidrec = new VVideoRec(toPlay); - ViewMan::getInstance()->addNoLock(vidrec); + ViewMan::getInstance()->add(vidrec); vidrec->draw(); vidrec->show(); vidrec->go(0); @@ -310,7 +310,7 @@ int VRecordingList::doResume() 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); @@ -386,7 +386,7 @@ int VRecordingList::handleCommand(int command) { VRecordingList* sub = new VRecordingList(this); sub->setDir(curDir); - ViewMan::getInstance()->addNoLock(sub); + ViewMan::getInstance()->add(sub); sub->draw(); sub->show(); @@ -404,7 +404,7 @@ int VRecordingList::handleCommand(int command) VRecordingMenu* v = new VRecordingMenu(); v->setParent(this); v->setRecording(current); - ViewMan::getInstance()->addNoLock(v); + ViewMan::getInstance()->add(v); v->draw(); v->show(); return 2; diff --git a/vrecordingmenu.cc b/vrecordingmenu.cc index d7f95d0..3335ac9 100644 --- a/vrecordingmenu.cc +++ b/vrecordingmenu.cc @@ -132,7 +132,7 @@ int VRecordingMenu::handleCommand(int command) } vi->create(490, 300); - ViewMan::getInstance()->addNoLock(vi); + ViewMan::getInstance()->add(vi); vi->draw(); vi->show(); @@ -161,7 +161,7 @@ int VRecordingMenu::handleCommand(int command) v->setScreenPos(220, 140); } - ViewMan::getInstance()->addNoLock(v); + ViewMan::getInstance()->add(v); v->draw(); v->show(); return 2; diff --git a/vvideolive.cc b/vvideolive.cc index 3beb850..f96b5bc 100644 --- a/vvideolive.cc +++ b/vvideolive.cc @@ -116,7 +116,7 @@ int VVideoLive::handleCommand(int command) case Remote::ZERO ... Remote::NINE: { VChannelSelect* v = new VChannelSelect(this, command); - viewman->addNoLock(v); + viewman->add(v); v->draw(); v->show(); } @@ -246,7 +246,7 @@ void VVideoLive::showUnavailable(int active) else { unavailable = 0; - ViewMan::getInstance()->removeView(unavailableView, 1); + ViewMan::getInstance()->removeView(unavailableView); unavailableView = NULL; } } @@ -274,7 +274,7 @@ void VVideoLive::stop(int noRemoveVLB) 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(); @@ -317,7 +317,7 @@ void VVideoLive::showEPG() { 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(); diff --git a/vwelcome.cc b/vwelcome.cc index ade1c41..0dd9827 100644 --- a/vwelcome.cc +++ b/vwelcome.cc @@ -192,7 +192,7 @@ void VWelcome::doChannelsList() VChannelList* vchan = new VChannelList(VDR::VIDEO); vchan->setList(chanList); - ViewMan::getInstance()->addNoLock(vchan); + ViewMan::getInstance()->add(vchan); vchan->draw(); vchan->show(); @@ -215,7 +215,7 @@ void VWelcome::doRadioList() VChannelList* vchan = new VChannelList(VDR::RADIO); vchan->setList(chanList); - ViewMan::getInstance()->addNoLock(vchan); + ViewMan::getInstance()->add(vchan); vchan->draw(); vchan->show(); } @@ -238,7 +238,7 @@ void VWelcome::doRecordingsList() viewWait->setOneLiner(tr("Downloading recordings list")); viewWait->draw(); viewWait->show(); - viewman->addNoLock(viewWait); + viewman->add(viewWait); VDR* vdr = VDR::getInstance(); @@ -249,21 +249,21 @@ void VWelcome::doRecordingsList() 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(); } diff --git a/wtextbox.cc b/wtextbox.cc index d64f5e9..33fb99d 100644 --- a/wtextbox.cc +++ b/wtextbox.cc @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2005 Brian Walton This file is part of VOMP. diff --git a/wtextbox.h b/wtextbox.h index bfbf865..1037d3e 100644 --- a/wtextbox.h +++ b/wtextbox.h @@ -1,5 +1,5 @@ /* - Copyright 2004-2005 Chris Tallon + Copyright 2005 Brian Walton This file is part of VOMP. -- 2.39.2