summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlouis <louis.braun@gmx.de>2016-05-04 16:21:42 +0200
committerlouis <louis.braun@gmx.de>2016-05-04 16:21:42 +0200
commit7994fc200ae7fd2562c367fdfd325f5a88bee3c8 (patch)
tree8945fcffbdda09b915143cd10080c1b3c0b97a1f
parent24cf03d3f87b98d4de214032abd2a8769ad002e1 (diff)
downloadvdr-plugin-skindesigner-7994fc200ae7fd2562c367fdfd325f5a88bee3c8.tar.gz
vdr-plugin-skindesigner-7994fc200ae7fd2562c367fdfd325f5a88bee3c8.tar.bz2
implemented epg2vdr support
-rw-r--r--Makefile2
-rw-r--r--coreengine/definitions.h13
-rw-r--r--coreengine/listelements.c43
-rw-r--r--coreengine/viewdisplaychannel.c6
-rw-r--r--coreengine/viewdisplaychannel.h2
-rw-r--r--coreengine/viewelementsdisplaychannel.c34
-rw-r--r--coreengine/viewelementsdisplaychannel.h5
-rw-r--r--coreengine/viewelementsdisplaymenu.c49
-rw-r--r--extensions/globaltimers.c233
-rw-r--r--extensions/globaltimers.h44
-rw-r--r--extensions/timers.c134
-rw-r--r--extensions/timers.h24
-rw-r--r--services/epgtimer.h121
-rw-r--r--skindesigner.c3
-rw-r--r--skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg89
-rw-r--r--skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg89
-rw-r--r--skins/estuary4vdr/xmlfiles/displaymenumain.xml4
-rw-r--r--skins/estuary4vdr/xmlfiles/displaymenutimers.xml2
-rw-r--r--skinskeleton/xmlfiles/displaymenumain.xml3
-rw-r--r--skinskeleton/xmlfiles/displaymenutimers.xml6
20 files changed, 688 insertions, 218 deletions
diff --git a/Makefile b/Makefile
index 2643049..a22169e 100644
--- a/Makefile
+++ b/Makefile
@@ -70,6 +70,7 @@ OBJS = $(PLUGIN).o \
extensions/cairoimage.o \
extensions/curlfuncs.o \
extensions/fontmanager.o \
+ extensions/globaltimers.o \
extensions/imagecache.o \
extensions/helpers.o \
extensions/imageloader.o \
@@ -80,7 +81,6 @@ OBJS = $(PLUGIN).o \
extensions/skinsetup.o \
extensions/skinrepo.o \
extensions/extrecinfo.o \
- extensions/timers.o \
coreengine/animation.o \
coreengine/attribute.o \
coreengine/attributes.o \
diff --git a/coreengine/definitions.h b/coreengine/definitions.h
index 5787615..ccb9acb 100644
--- a/coreengine/definitions.h
+++ b/coreengine/definitions.h
@@ -504,6 +504,7 @@ enum class eDMTimersLT {
channelid,
channellogoexists,
isremotetimer,
+ remotehost,
count
};
@@ -898,6 +899,10 @@ enum class eLeMenuTimersST {
eventtitle,
eventstart,
eventstop,
+ state,
+ stateinfo,
+ action,
+ vdrname,
count
};
@@ -914,6 +919,8 @@ enum class eLeMenuTimersIT {
flagvps,
flagrecording,
flagpending,
+ isvdrrunning,
+ isremote,
count
};
@@ -933,6 +940,10 @@ enum class eCeMenuTimersST {
eventdescription,
posterpath,
bannerpath,
+ state,
+ stateinfo,
+ action,
+ vdrname,
count
};
@@ -957,6 +968,8 @@ enum class eCeMenuTimersIT {
hasbanner,
bannerwidth,
bannerheight,
+ isvdrrunning,
+ isremote,
count
};
diff --git a/coreengine/listelements.c b/coreengine/listelements.c
index 1d9d015..e5dfd93 100644
--- a/coreengine/listelements.c
+++ b/coreengine/listelements.c
@@ -1,5 +1,6 @@
#include "listelements.h"
#include "../config.h"
+#include "../services/epgtimer.h"
#include <sstream>
#include <algorithm>
@@ -1181,6 +1182,10 @@ void cLeMenuTimers::SetTokenContainer(void) {
tokenContainer->DefineStringToken("{eventtitle}", (int)eLeMenuTimersST::eventtitle);
tokenContainer->DefineStringToken("{eventstart}", (int)eLeMenuTimersST::eventstart);
tokenContainer->DefineStringToken("{eventstop}", (int)eLeMenuTimersST::eventstop);
+ tokenContainer->DefineStringToken("{state}", (int)eLeMenuTimersST::state);
+ tokenContainer->DefineStringToken("{stateinfo}", (int)eLeMenuTimersST::stateinfo);
+ tokenContainer->DefineStringToken("{action}", (int)eLeMenuTimersST::action);
+ tokenContainer->DefineStringToken("{vdrname}", (int)eLeMenuTimersST::vdrname);
tokenContainer->DefineIntToken("{nummenuitem}", (int)eLeMenuTimersIT::nummenuitem);
tokenContainer->DefineIntToken("{current}", (int)eLeMenuTimersIT::current);
tokenContainer->DefineIntToken("{separator}", (int)eLeMenuTimersIT::separator);
@@ -1193,6 +1198,8 @@ void cLeMenuTimers::SetTokenContainer(void) {
tokenContainer->DefineIntToken("{flagvps}", (int)eLeMenuTimersIT::flagvps);
tokenContainer->DefineIntToken("{flagrecording}", (int)eLeMenuTimersIT::flagrecording);
tokenContainer->DefineIntToken("{flagpending}", (int)eLeMenuTimersIT::flagpending);
+ tokenContainer->DefineIntToken("{isvdrrunning}", (int)eLeMenuTimersIT::isvdrrunning);
+ tokenContainer->DefineIntToken("{isremote}", (int)eLeMenuTimersIT::isremote);
InheritTokenContainer();
}
@@ -1279,6 +1286,21 @@ bool cLeMenuTimers::Parse(bool forced) {
tokenContainer->AddStringToken((int)eLeMenuTimersST::eventstart, *event->GetTimeString());
tokenContainer->AddStringToken((int)eLeMenuTimersST::eventstop, *event->GetEndTimeString());
}
+
+ cEpgTimer_Interface_V1* epgTimer;
+ if (epgTimer = dynamic_cast<cEpgTimer_Interface_V1*>((cTimer*)timer)) {
+ tokenContainer->AddIntToken((int)eLeMenuTimersIT::isvdrrunning, epgTimer->isVdrRunning());
+ tokenContainer->AddIntToken((int)eLeMenuTimersIT::isremote, epgTimer->isRemote());
+ stringstream state;
+ state << epgTimer->State();
+ tokenContainer->AddStringToken((int)eLeMenuTimersST::state, state.str().c_str());
+ tokenContainer->AddStringToken((int)eLeMenuTimersST::stateinfo, epgTimer->StateInfo());
+ tokenContainer->AddStringToken((int)eLeMenuTimersST::vdrname, epgTimer->VdrName());
+ stringstream action;
+ action << epgTimer->Action();
+ tokenContainer->AddStringToken((int)eLeMenuTimersST::action, action.str().c_str());
+ }
+
return true;
}
@@ -1318,6 +1340,10 @@ void cCeMenuTimers::SetTokenContainer(void) {
tokenContainer->DefineStringToken("{eventdescription}", (int)eCeMenuTimersST::eventdescription);
tokenContainer->DefineStringToken("{posterpath}", (int)eCeMenuTimersST::posterpath);
tokenContainer->DefineStringToken("{bannerpath}", (int)eCeMenuTimersST::bannerpath);
+ tokenContainer->DefineStringToken("{state}", (int)eCeMenuTimersST::state);
+ tokenContainer->DefineStringToken("{stateinfo}", (int)eCeMenuTimersST::stateinfo);
+ tokenContainer->DefineStringToken("{action}", (int)eCeMenuTimersST::action);
+ tokenContainer->DefineStringToken("{vdrname}", (int)eCeMenuTimersST::vdrname);
tokenContainer->DefineIntToken("{menuitemx}", (int)eCeMenuTimersIT::menuitemx);
tokenContainer->DefineIntToken("{menuitemy}", (int)eCeMenuTimersIT::menuitemy);
tokenContainer->DefineIntToken("{menuitemwidth}", (int)eCeMenuTimersIT::menuitemwidth);
@@ -1338,6 +1364,8 @@ void cCeMenuTimers::SetTokenContainer(void) {
tokenContainer->DefineIntToken("{hasbanner}", (int)eCeMenuTimersIT::hasbanner);
tokenContainer->DefineIntToken("{bannerwidth}", (int)eCeMenuTimersIT::bannerwidth);
tokenContainer->DefineIntToken("{bannerheight}", (int)eCeMenuTimersIT::bannerheight);
+ tokenContainer->DefineIntToken("{isvdrrunning}", (int)eCeMenuTimersIT::isvdrrunning);
+ tokenContainer->DefineIntToken("{isremote}", (int)eCeMenuTimersIT::isremote);
InheritTokenContainer();
}
@@ -1423,6 +1451,21 @@ bool cCeMenuTimers::Parse(bool forced) {
if (LoadFullScrapInfo(event, NULL))
SetScraperPosterBannerTimer(tokenContainer);
}
+
+ cEpgTimer_Interface_V1* epgTimer;
+ if (epgTimer = dynamic_cast<cEpgTimer_Interface_V1*>((cTimer*)timer)) {
+ tokenContainer->AddIntToken((int)eCeMenuTimersIT::isvdrrunning, epgTimer->isVdrRunning());
+ tokenContainer->AddIntToken((int)eCeMenuTimersIT::isremote, epgTimer->isRemote());
+ stringstream state;
+ state << epgTimer->State();
+ tokenContainer->AddStringToken((int)eCeMenuTimersST::state, state.str().c_str());
+ tokenContainer->AddStringToken((int)eCeMenuTimersST::stateinfo, epgTimer->StateInfo());
+ tokenContainer->AddStringToken((int)eCeMenuTimersST::vdrname, epgTimer->VdrName());
+ stringstream action;
+ action << epgTimer->Action();
+ tokenContainer->AddStringToken((int)eCeMenuTimersST::action, action.str().c_str());
+ }
+
return true;
}
diff --git a/coreengine/viewdisplaychannel.c b/coreengine/viewdisplaychannel.c
index 38c444f..5a6bb68 100644
--- a/coreengine/viewdisplaychannel.c
+++ b/coreengine/viewdisplaychannel.c
@@ -68,6 +68,7 @@ void cViewChannel::SetViewElementObjects(void) {
else if (dynamic_cast<cVeDcEpgInfo*>(viewElements[i]))
{
veEpgInfo = dynamic_cast<cVeDcEpgInfo*>(viewElements[i]);
+ veEpgInfo->SetGlobalTimers(&globalTimers);
}
else if (dynamic_cast<cVeDcProgressBar*>(viewElements[i]))
{
@@ -76,6 +77,7 @@ void cViewChannel::SetViewElementObjects(void) {
else if (dynamic_cast<cVeDcStatusInfo*>(viewElements[i]))
{
veStatusInfo = dynamic_cast<cVeDcStatusInfo*>(viewElements[i]);
+ veStatusInfo->SetGlobalTimers(&globalTimers);
}
else if (dynamic_cast<cVeDcScraperContent*>(viewElements[i]))
{
@@ -102,6 +104,7 @@ void cViewChannel::ClearVariables(void) {
displayChannelGroups = false;
if (veCustomTokens)
veCustomTokens->Reset();
+ globalTimers.ClearTimers();
}
void cViewChannel::SetChannel(const cChannel *channel, int number) {
@@ -141,6 +144,9 @@ void cViewChannel::SetChannel(const cChannel *channel, int number) {
}
void cViewChannel::SetEvents(const cEvent *present, const cEvent *following) {
+ if (init) {
+ globalTimers.LoadTimers();
+ }
Clear((int)eVeDisplayChannel::epginfo);
Clear((int)eVeDisplayChannel::progressbar);
Clear((int)eVeDisplayChannel::scrapercontent);
diff --git a/coreengine/viewdisplaychannel.h b/coreengine/viewdisplaychannel.h
index 2170e40..e05217e 100644
--- a/coreengine/viewdisplaychannel.h
+++ b/coreengine/viewdisplaychannel.h
@@ -2,6 +2,7 @@
#define __VIEWDISPLAYCHANNEL_H
#include "view.h"
+#include "../extensions/globaltimers.h"
class cViewChannel : public cView {
private:
@@ -16,6 +17,7 @@ private:
cVeDcEcmInfo *veEcmInfo;
bool channelChange;
bool displayChannelGroups;
+ cGlobalTimers globalTimers;
void SetViewElements(void);
void ClearVariables(void);
void SetViewElementObjects(void);
diff --git a/coreengine/viewelementsdisplaychannel.c b/coreengine/viewelementsdisplaychannel.c
index 3384a53..875a588 100644
--- a/coreengine/viewelementsdisplaychannel.c
+++ b/coreengine/viewelementsdisplaychannel.c
@@ -1,7 +1,6 @@
#include "viewelementsdisplaychannel.h"
#include "../config.h"
#include "../extensions/helpers.h"
-#include "../extensions/timers.h"
#include "../services/scraper2vdr.h"
/******************************************************************
@@ -111,6 +110,7 @@ const char *cVeDcChannelGroup::GetChannelSep(const cChannel *c, bool prev) {
* cVeDcEpgInfo
******************************************************************/
cVeDcEpgInfo::cVeDcEpgInfo(void) {
+ globalTimers = NULL;
}
cVeDcEpgInfo::~cVeDcEpgInfo(void) {
@@ -176,24 +176,14 @@ void cVeDcEpgInfo::Close(void) {
bool cVeDcEpgInfo::EventHasTimer(const cEvent *e) {
if (!e) return false;
- int timerCount = 0;
- // BLOCK for LOCK_TIMERS_READ scope !!
- {
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_READ;
- timerCount = Timers->Count();
-#else
- timerCount = Timers.Count();
-#endif
- }
- cGlobalSortedTimers SortedTimers(timerCount); // local and remote timers
bool hasTimer = e->HasTimer();
- for (int i = 0; i < SortedTimers.Size() && !hasTimer; i++)
- if (const cTimer *Timer = SortedTimers[i])
+ for (int i = 0; i < globalTimers->Size() && !hasTimer; i++)
+ if (const cTimer *Timer = globalTimers->At(i))
if (Timer->Channel()->GetChannelID() == e->ChannelID())
if (const cEvent *timerEvent = Timer->Event())
if (e->EventID() == timerEvent->EventID())
hasTimer = true;
+
return hasTimer;
}
@@ -328,19 +318,9 @@ void cVeDcStatusInfo::Set(const cChannel *c) {
bool isDolby = c->Dpid(0);
bool isEncrypted = c->Ca();
bool isRecording = cRecordControls::Active();
- int timerCount = 0;
- // BLOCK for LOCK_TIMERS_READ scope !!
- {
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_READ;
- timerCount = Timers->Count();
-#else
- timerCount = Timers.Count();
-#endif
- }
- cGlobalSortedTimers SortedTimers(timerCount); // local and remote timers
- for (int i = 0; i < SortedTimers.Size() && !isRecording; i++)
- if (const cTimer *Timer = SortedTimers[i])
+
+ for (int i = 0; i < globalTimers->Size() && !isRecording; i++)
+ if (const cTimer *Timer = globalTimers->At(i))
if (Timer->Recording())
isRecording = true;
diff --git a/coreengine/viewelementsdisplaychannel.h b/coreengine/viewelementsdisplaychannel.h
index 3505201..799456d 100644
--- a/coreengine/viewelementsdisplaychannel.h
+++ b/coreengine/viewelementsdisplaychannel.h
@@ -3,6 +3,7 @@
#include "viewelement.h"
#include "../extensions/scrapmanager.h"
+#include "../extensions/globaltimers.h"
#include "../services/dvbapi.h"
/******************************************************************
@@ -33,10 +34,12 @@ public:
******************************************************************/
class cVeDcEpgInfo : public cViewElement {
private:
+ cGlobalTimers *globalTimers;
bool EventHasTimer(const cEvent *e);
public:
cVeDcEpgInfo(void);
virtual ~cVeDcEpgInfo(void);
+ void SetGlobalTimers(cGlobalTimers *globalTimers) { this->globalTimers = globalTimers; };
void SetTokenContainer(void);
void Set(const cEvent *p, const cEvent *f);
void Close(void);
@@ -63,10 +66,12 @@ public:
******************************************************************/
class cVeDcStatusInfo : public cViewElement {
private:
+ cGlobalTimers *globalTimers;
bool CheckMails(void);
public:
cVeDcStatusInfo(void);
virtual ~cVeDcStatusInfo(void);
+ void SetGlobalTimers(cGlobalTimers *globalTimers) { this->globalTimers = globalTimers; };
void SetTokenContainer(void);
void Set(const cChannel *c);
};
diff --git a/coreengine/viewelementsdisplaymenu.c b/coreengine/viewelementsdisplaymenu.c
index cd2b8fc..51349c7 100644
--- a/coreengine/viewelementsdisplaymenu.c
+++ b/coreengine/viewelementsdisplaymenu.c
@@ -1,8 +1,8 @@
#include "viewelementsdisplaymenu.h"
#include "../config.h"
#include <vdr/videodir.h>
-#include "../extensions/timers.h"
#include "../extensions/helpers.h"
+#include "../extensions/globaltimers.h"
#include <sys/sysinfo.h>
#include <fstream>
#include <iostream>
@@ -336,6 +336,7 @@ void cVeDmTimers::SetTokenContainer(void) {
tokenContainer->DefineLoopToken("{timers[channelid]}", (int)eDMTimersLT::channelid);
tokenContainer->DefineLoopToken("{timers[channellogoexists]}", (int)eDMTimersLT::channellogoexists);
tokenContainer->DefineLoopToken("{timers[isremotetimer]}", (int)eDMTimersLT::isremotetimer);
+ tokenContainer->DefineLoopToken("{timers[remotehost]}", (int)eDMTimersLT::remotehost);
tokenContainer->DefineIntToken("{numtimers}", (int)eDMTimersIT::numtimers);
tokenContainer->DefineIntToken("{numtimerconflicts}", (int)eDMTimersIT::numtimerconflicts);
tokenContainer->DefineIntToken("{timer1exists}", (int)eDMTimersIT::timer1exists);
@@ -361,21 +362,15 @@ bool cVeDmTimers::Parse(bool forced) {
if (!cViewElement::Parse(forced))
return false;
tokenContainer->Clear();
+
+ cGlobalTimers globalTimers;
+ globalTimers.LoadTimers();
+ globalTimers.SortTimers();
+ globalTimers.MarkLocalTimers();
- int timerCount = 0;
- // BLOCK for LOCK_TIMERS_READ scope !!
- {
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_READ;
- timerCount = Timers->Count();
-#else
- timerCount = Timers.Count();
-#endif
- }
- cGlobalSortedTimers SortedTimers(timerCount); // local and remote timers
- int numTimers = SortedTimers.Size();
+ int numTimers = globalTimers.Size();
tokenContainer->AddIntToken((int)eDMTimersIT::numtimers, numTimers);
- tokenContainer->AddIntToken((int)eDMTimersIT::numtimerconflicts, SortedTimers.NumTimerConfilicts());
+ tokenContainer->AddIntToken((int)eDMTimersIT::numtimerconflicts, globalTimers.NumTimerConfilicts());
for (int i=0; i<15; i++) {
if (i < numTimers) {
tokenContainer->AddIntToken(i+2, true);
@@ -391,8 +386,9 @@ bool cVeDmTimers::Parse(bool forced) {
for (int i = 0; i < numTimers; i++) {
if (i >=15)
break;
- const cTimer *Timer = SortedTimers[i];
- tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::isremotetimer, SortedTimers.IsRemoteTimer(i) ? "1" : "0");
+ const cTimer *Timer = globalTimers[i];
+ tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::isremotetimer, globalTimers.IsRemoteTimer(i) ? "1" : "0");
+ tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::remotehost, globalTimers.RemoteHost(i));
const cEvent *event = Timer->Event();
if (event) {
tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::title, event->Title());
@@ -434,8 +430,8 @@ bool cVeDmTimers::Parse(bool forced) {
timerDate = cString::sprintf("VPS %s", *timerDate);
}
tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::datetime, *timerDate);
- tokenContainer->AddLoopToken(timerIndex, i, (int)eDMTimersLT::isremotetimer, SortedTimers.IsRemoteTimer(i) ? "1" : "0");
}
+
SetDirty();
return true;
}
@@ -893,20 +889,12 @@ bool cVeDmLastrecordings::Parse(bool forced) {
return false;
tokenContainer->Clear();
- int numTimers = 0;
- // BLOCK for LOCK_TIMERS_READ scope !!
- {
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_READ;
- numTimers = Timers->Count();
-#else
- numTimers = Timers.Count();
-#endif
- }
-
- cGlobalSortedTimers SortedTimers(numTimers); // local and remote timers
+
+ cGlobalTimers globalTimers;
+ globalTimers.LoadTimers();
+
//set number of timers so that it is possible to adapt this viewelement accordingly
- tokenContainer->AddIntToken((int)eDMLastrecordingsIT::numtimers, SortedTimers.Size());
+ tokenContainer->AddIntToken((int)eDMLastrecordingsIT::numtimers, globalTimers.Size());
list<const cRecording*> orderedRecs;
@@ -980,6 +968,7 @@ bool cVeDmLastrecordings::Parse(bool forced) {
if (i == MAX_RECORDINGS)
break;
}
+
SetDirty();
return true;
}
diff --git a/extensions/globaltimers.c b/extensions/globaltimers.c
new file mode 100644
index 0000000..6e7263e
--- /dev/null
+++ b/extensions/globaltimers.c
@@ -0,0 +1,233 @@
+#include "globaltimers.h"
+#include "../services/epgsearch.h"
+#include "../services/remotetimers.h"
+#include "../services/epgtimer.h"
+
+static int CompareTimers(const void *a, const void *b) {
+ return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
+}
+
+bool cGlobalTimers::initial = true;
+cRemoteTimerRefresh *cGlobalTimers::remoteTimerRefresh = NULL;
+
+cGlobalTimers::cGlobalTimers(void) : cVector<const cTimer*>(0) {
+ pEpg2Vdr = cPluginManager::GetPlugin("epg2vdr");
+ pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
+ pEpgSearch = cPluginManager::GetPlugin("epgsearch");
+ localTimer = NULL;
+ isEpg2VdrTimers = false;
+}
+
+cGlobalTimers::~cGlobalTimers(void) {
+ if (localTimer) {
+ delete[] localTimer;
+ }
+ ClearTimers();
+}
+
+void cGlobalTimers::LoadTimers(void) {
+ uint64_t start = cTimeMs::Now();
+ isEpg2VdrTimers = false;
+ bool epg2vdrOk = false;
+ if (pEpg2Vdr) {
+ epg2vdrOk = SetEpg2VdrTimers();
+ }
+ if (!epg2vdrOk) {
+ SetLocalTimers();
+ if (pRemoteTimers) {
+ SetRemoteTimers(initial);
+ }
+ }
+ esyslog("skindesigner: loaded %d timers, needed %d ms", Size(), cTimeMs::Now() - start);
+ initial = false;
+}
+
+void cGlobalTimers::SortTimers(void) {
+ Sort(CompareTimers);
+}
+
+void cGlobalTimers::MarkLocalTimers(void) {
+ if (isEpg2VdrTimers)
+ return;
+
+ if (localTimer) {
+ delete[] localTimer;
+ localTimer = NULL;
+ }
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+ LOCK_TIMERS_READ;
+ const cTimers* timers = Timers;
+#else
+ const cTimers* timers = &Timers;
+#endif
+ int numTimers = Size();
+ if (numTimers > 0) {
+ localTimer = new bool[numTimers];
+ for (int i=0; i < numTimers; i++) {
+ if (!pRemoteTimers) {
+ localTimer[i] = true;
+ } else {
+ localTimer[i] = false;
+ for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) {
+ if (Timer == At(i)) {
+ localTimer[i] = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void cGlobalTimers::SetLocalTimers(void) {
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+ LOCK_TIMERS_READ;
+ const cTimers* timers = Timers;
+#else
+ const cTimers* timers = &Timers;
+#endif
+ for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) {
+ if (Timer->HasFlags(tfActive))
+ Append(Timer);
+ }
+}
+
+void cGlobalTimers::SetRemoteTimers(bool initial) {
+ if (initial) {
+ cString errorMsg;
+ pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
+ }
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+ LOCK_SCHEDULES_READ;
+ const cSchedules* schedules = Schedules;
+#else
+ cSchedulesLock schedulesLock;
+ const cSchedules* schedules = (cSchedules*)cSchedules::Schedules(schedulesLock);
+#endif
+ cTimer* remoteTimer = NULL;
+ while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) {
+ remoteTimer->SetEventFromSchedule(schedules); // make sure the event is current
+ if (remoteTimer->HasFlags(tfActive))
+ Append(remoteTimer);
+ }
+}
+
+bool cGlobalTimers::SetEpg2VdrTimers(void) {
+ bool ok = false;
+ cEpgTimer_Service_V1 data;
+ if (pEpg2Vdr->Service(EPG2VDR_TIMER_SERVICE, &data)) {
+ for (std::list<cEpgTimer_Interface_V1*>::iterator it = data.epgTimers.begin(); it != data.epgTimers.end(); ++it) {
+ ok = true;
+ isEpg2VdrTimers = true;
+ if ((*it)->HasFlags(tfActive)) {
+ Append(*it);
+ }
+ }
+ }
+ return ok;
+}
+
+int cGlobalTimers::NumTimerConfilicts(void) {
+ int numConflicts = 0;
+ if (pEpgSearch) {
+ Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0;
+ if (serviceData) {
+ serviceData->nextConflict = 0;
+ serviceData->relevantConflicts = 0;
+ serviceData->totalConflicts = 0;
+ pEpgSearch->Service("Epgsearch-lastconflictinfo-v1.0", serviceData);
+ if (serviceData->relevantConflicts > 0) {
+ numConflicts = serviceData->relevantConflicts;
+ }
+ delete serviceData;
+ }
+ }
+ return numConflicts;
+}
+
+bool cGlobalTimers::IsRemoteTimer(int i) {
+ if (isEpg2VdrTimers) {
+ cEpgTimer_Interface_V1* epgTimer;
+ if (epgTimer = dynamic_cast<cEpgTimer_Interface_V1*>((cTimer*)At(i)))
+ return !epgTimer->isLocal();
+ else
+ return false;
+ }
+ if (!localTimer)
+ return true;
+ if (i >= Size())
+ return true;
+ return !(localTimer[i]);
+}
+
+const char* cGlobalTimers::RemoteHost(int i) {
+ if (isEpg2VdrTimers) {
+ cEpgTimer_Interface_V1* epgTimer;
+ if (epgTimer = dynamic_cast<cEpgTimer_Interface_V1*>((cTimer*)At(i)))
+ return epgTimer->VdrName();
+ }
+ return "";
+}
+
+void cGlobalTimers::ClearTimers(void) {
+ if (isEpg2VdrTimers) {
+ int size = Size();
+ for (int i=0; i<size; i++) {
+ delete At(i);
+ }
+ }
+ Clear();
+}
+
+void cGlobalTimers::StartRefreshThread(void) {
+ if (remoteTimerRefresh == NULL) {
+ remoteTimerRefresh = new cRemoteTimerRefresh();
+ }
+}
+
+void cGlobalTimers::StopRefreshThread(void) {
+ if (!remoteTimerRefresh)
+ return;
+ delete remoteTimerRefresh;
+ remoteTimerRefresh = NULL;
+ initial = true;
+}
+
+/*************************************************************************
+* cRemoteTimerRefresh
+*************************************************************************/
+cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") {
+ pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
+ if (pRemoteTimers)
+ Start();
+}
+
+cRemoteTimerRefresh::~cRemoteTimerRefresh(void) {
+ Cancel(-1);
+ while (Active())
+ cCondWait::SleepMs(10);
+}
+
+void cRemoteTimerRefresh::Action(void) {
+#define REFESH_INTERVALL_MS 30000
+ int sleepSlice = 1000;
+ int slept = 0;
+ while (Running()) {
+ while (Running() && slept < REFESH_INTERVALL_MS) {
+ cCondWait::SleepMs(sleepSlice);
+ slept += sleepSlice;
+ }
+ slept = 0;
+ // make sure that no timer is currently being edited
+ if (!cOsd::IsOpen() && Running()) {
+ cString errorMsg;
+ pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
+#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
+ LOCK_TIMERS_WRITE;
+ Timers->SetModified();
+#else
+ Timers.SetModified();
+#endif
+ }
+ }
+}
diff --git a/extensions/globaltimers.h b/extensions/globaltimers.h
new file mode 100644
index 0000000..9f722d8
--- /dev/null
+++ b/extensions/globaltimers.h
@@ -0,0 +1,44 @@
+#ifndef __GLOBALTIMERS_H
+#define __GLOBALTIMERS_H
+
+#include <vdr/timers.h>
+#include <vdr/plugin.h>
+
+class cRemoteTimerRefresh;
+
+class cGlobalTimers : public cVector<const cTimer *> {
+ private:
+ static bool initial;
+ static cRemoteTimerRefresh *remoteTimerRefresh;
+ bool *localTimer;
+ cPlugin *pEpg2Vdr;
+ cPlugin *pRemoteTimers;
+ cPlugin *pEpgSearch;
+ bool isEpg2VdrTimers;
+ void SetLocalTimers(void);
+ void SetRemoteTimers(bool initial);
+ bool SetEpg2VdrTimers(void);
+ public:
+ cGlobalTimers(void);
+ virtual ~cGlobalTimers(void);
+ void LoadTimers(void);
+ void SortTimers(void);
+ void MarkLocalTimers(void);
+ int NumTimerConfilicts(void);
+ bool IsRemoteTimer(int i);
+ const char* RemoteHost(int i);
+ void ClearTimers(void);
+ static void StartRefreshThread(void);
+ static void StopRefreshThread(void);
+};
+
+class cRemoteTimerRefresh: public cThread {
+ private:
+ cPlugin* pRemoteTimers;
+ protected:
+ virtual void Action(void);
+ public:
+ cRemoteTimerRefresh(void);
+ virtual ~cRemoteTimerRefresh(void);
+};
+#endif //__GLOBALTIMERS_H
diff --git a/extensions/timers.c b/extensions/timers.c
deleted file mode 100644
index 4f81b2a..0000000
--- a/extensions/timers.c
+++ /dev/null
@@ -1,134 +0,0 @@
-#include "timers.h"
-#include "../services/epgsearch.h"
-#include "../services/remotetimers.h"
-
-static int CompareTimers(const void *a, const void *b) {
- return (*(const cTimer **)a)->Compare(**(const cTimer **)b);
-}
-
-cGlobalSortedTimers::cGlobalSortedTimers(int timerCount, bool forceRefresh) : cVector<const cTimer*>(timerCount) {
- static bool initial = true;
- static cRemoteTimerRefresh *remoteTimerRefresh = NULL;
- localTimer = NULL;
-
- if (forceRefresh)
- initial = true;
- //check if remotetimers plugin is available
- static cPlugin* pRemoteTimers = cPluginManager::GetPlugin("remotetimers");
-
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_READ;
- LOCK_SCHEDULES_READ;
- const cTimers* timers = Timers;
- const cSchedules* schedules = Schedules;
-#else
- const cTimers* timers = &Timers;
- cSchedulesLock schedulesLock;
- const cSchedules* schedules = (cSchedules*)cSchedules::Schedules(schedulesLock);
-#endif
-
- if (pRemoteTimers && initial) {
- cString errorMsg;
- pRemoteTimers->Service("RemoteTimers::RefreshTimers-v1.0", &errorMsg);
- initial = false;
- }
-
- for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) {
- if (Timer->HasFlags(tfActive))
- Append(Timer);
- }
-
- //if remotetimers plugin is available, take timers also from him
- if (pRemoteTimers) {
- cTimer* remoteTimer = NULL;
- while (pRemoteTimers->Service("RemoteTimers::ForEach-v1.0", &remoteTimer) && remoteTimer != NULL) {
- remoteTimer->SetEventFromSchedule(schedules); // make sure the event is current
- if (remoteTimer->HasFlags(tfActive))
- Append(remoteTimer);
- }
- }
-
- Sort(CompareTimers);
-
- int numTimers = Size();
- if (numTimers > 0) {
- localTimer = new bool[numTimers];
- for (int i=0; i < numTimers; i++) {
- if (!pRemoteTimers) {
- localTimer[i] = true;
- } else {
- localTimer[i] = false;
- for (const cTimer *Timer = timers->First(); Timer; Timer = timers->Next(Timer)) {
- if (Timer == At(i)) {
- localTimer[i] = true;
- break;
- }
- }
- }
- }
- }
-
- if (pRemoteTimers && (remoteTimerRefresh == NULL))
- remoteTimerRefresh = new cRemoteTimerRefresh();
-}
-
-cGlobalSortedTimers::~cGlobalSortedTimers(void) {
- if (localTimer) {
- delete[] localTimer;
- }
-}
-
-bool cGlobalSortedTimers::IsRemoteTimer(int i) {
- if (!localTimer)
- return true;
- if (i >= Size())
- return true;
- return !(localTimer[i]);
-}
-
-
-int cGlobalSortedTimers::NumTimerConfilicts(void) {
- int numConflicts = 0;
- cPlugin *p = cPluginManager::GetPlugin("epgsearch");
- if (p) {
- Epgsearch_lastconflictinfo_v1_0 *serviceData = new Epgsearch_lastconflictinfo_v1_0;
- if (serviceData) {
- serviceData->nextConflict = 0;
- serviceData->relevantConflicts = 0;
- serviceData->totalConflicts = 0;
- p->Service("Epgsearch-lastconflictinfo-v1.0", serviceData);
- if (serviceData->relevantConflicts > 0) {
- numConflicts = serviceData->relevantConflicts;
- }
- delete serviceData;
- }
- }
- return numConflicts;
-}
-
-cRemoteTimerRefresh::cRemoteTimerRefresh(): cThread("skindesigner: RemoteTimers::RefreshTimers") {
- Start();
-}
-
-cRemoteTimerRefresh::~cRemoteTimerRefresh(void) {
- Cancel(-1);
- while (Active())
- cCondWait::SleepMs(10);
-}
-
-void cRemoteTimerRefresh::Action(void) {
-#define REFESH_INTERVALL_MS 30000
- while (Running()) {
- cCondWait::SleepMs(REFESH_INTERVALL_MS);
- // make sure that no timer is currently being edited
- if (!cOsd::IsOpen()) {
- cGlobalSortedTimers(true);
-#if defined (APIVERSNUM) && (APIVERSNUM >= 20301)
- LOCK_TIMERS_WRITE;
- Timers->SetModified();
-#else
- Timers.SetModified();
-#endif
- }
- }
-}
diff --git a/extensions/timers.h b/extensions/timers.h
deleted file mode 100644
index fdbca31..0000000
--- a/extensions/timers.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __NOPACITY_TIMERS_H
-#define __NOPACITY_TIMERS_H
-
-#include <vdr/timers.h>
-#include <vdr/plugin.h>
-
-class cGlobalSortedTimers : public cVector<const cTimer *> {
- private:
- bool *localTimer;
- public:
- cGlobalSortedTimers(int timerCount, bool forceRefresh = false);
- virtual ~cGlobalSortedTimers(void);
- bool IsRemoteTimer(int i);
- int NumTimerConfilicts(void);
-};
-
-class cRemoteTimerRefresh: public cThread {
- protected:
- virtual void Action(void);
- public:
- cRemoteTimerRefresh(void);
- virtual ~cRemoteTimerRefresh(void);
-};
-#endif //__NOPACITY_TIMERS_H
diff --git a/services/epgtimer.h b/services/epgtimer.h
new file mode 100644
index 0000000..89e318c
--- /dev/null
+++ b/services/epgtimer.h
@@ -0,0 +1,121 @@
+/*
+ * service.h: EPG2VDR plugin for the Video Disk Recorder
+ *
+ * See the README file for copyright information and how to reach the author.
+ *
+ */
+
+#ifndef _SERVICE_H_
+#define _SERVICE_H_
+
+#include <vdr/timers.h>
+#include <vdr/epg.h>
+
+#include <list>
+
+//***************************************************************************
+// Timer - Skin Interface
+//***************************************************************************
+
+class cEpgEvent_Interface_V1 : public cEvent
+{
+ public:
+
+ cEpgEvent_Interface_V1(tEventID EventID)
+ : cEvent(EventID) {}
+
+ // #TODO ... getter
+
+ protected:
+
+ // #TODO ... attributes
+};
+
+//***************************************************************************
+// Timer - Skin Interface
+//***************************************************************************
+
+class cEpgTimer_Interface_V1 : public cTimer
+{
+ public:
+
+ cEpgTimer_Interface_V1(bool Instant = false, bool Pause = false, cChannel* Channel = 0)
+ : cTimer(Instant, Pause, Channel) {}
+
+ long TimerId() { return timerid; }
+ long EventId() { return eventid; }
+ const char* VdrName() { return vdrName ? vdrName : ""; }
+ const char* VdrUuid() { return vdrUuid ? vdrUuid : ""; }
+ int isVdrRunning() { return vdrRunning; }
+ int isLocal() { return local; }
+ int isRemote() { return !isLocal(); }
+
+ char State() { return state; }
+ const char* StateInfo() { return stateInfo ? stateInfo : ""; }
+ char Action() { return action; }
+
+ protected:
+
+ long timerid;
+ long eventid;
+
+ char* vdrName;
+ char* vdrUuid;
+ int local;
+ int vdrRunning;
+
+ char state;
+ char* stateInfo;
+ char action;
+};
+
+//***************************************************************************
+// Timer - Service Interface
+//***************************************************************************
+
+struct cEpgTimer_Service_V1
+{
+ std::list<cEpgTimer_Interface_V1*> epgTimers;
+};
+
+#define EPG2VDR_TIMER_SERVICE "Epg2Vdr_Timer_Service-v1.0"
+
+#ifdef EPG2VDR
+
+//***************************************************************************
+// Class cEpgEvent
+//***************************************************************************
+
+class cEpgEvent : public cEpgEvent_Interface_V1
+{
+ public:
+
+ cEpgEvent(tEventID EventID);
+ virtual ~cEpgEvent() {}
+
+ // #TODO ... setter
+};
+
+//***************************************************************************
+// Class cEpgTimer
+//***************************************************************************
+
+class cEpgTimer : public cEpgTimer_Interface_V1
+{
+ public:
+
+ cEpgTimer(bool Instant = false, bool Pause = false, cChannel* Channel = 0);
+ virtual ~cEpgTimer();
+
+ void setTimerId(long id) { timerid = id; }
+ void setEventId(long id) { eventid = id; }
+ void setState(char s, const char* info);
+ void setAction(char a);
+ void setVdr(const char* name, const char* uuid = 0, int running = 0);
+};
+
+#endif // EPG2VDR
+
+//***************************************************************************
+
+#endif // _SERVICE_H_
diff --git a/skindesigner.c b/skindesigner.c
index 83aa288..56c97b9 100644
--- a/skindesigner.c
+++ b/skindesigner.c
@@ -13,6 +13,7 @@
#include "designer.h"
#include "setup.h"
#include "libskindesignerapi/skindesignerapi.h"
+#include "extensions/globaltimers.h"
#if defined(APIVERSNUM) && APIVERSNUM < 20200
#error "VDR-2.2.0 API version or greater is required!"
@@ -111,6 +112,7 @@ bool cPluginSkinDesigner::Initialize(void) {
bool cPluginSkinDesigner::Start(void) {
cXmlParser::InitLibXML();
cImageImporterSVG::InitLibRSVG();
+ cGlobalTimers::StartRefreshThread();
bool trueColorAvailable = true;
if (!cOsdProvider::SupportsTrueColor()) {
@@ -164,6 +166,7 @@ void cPluginSkinDesigner::Stop(void) {
delete fontManager;
delete plgManager;
cXmlParser::CleanupLibXML();
+ cGlobalTimers::StopRefreshThread();
}
void cPluginSkinDesigner::Housekeeping(void) {
diff --git a/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg
new file mode 100644
index 0000000..4e1f43a
--- /dev/null
+++ b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer.svg
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Capa_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 484.6 484.6"
+ style="enable-background:new 0 0 484.6 484.6;"
+ xml:space="preserve"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="ico_remotetimer.svg"><metadata
+ id="metadata59"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs57" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="1017"
+ id="namedview55"
+ showgrid="false"
+ inkscape:zoom="0.48699958"
+ inkscape:cx="-13.347034"
+ inkscape:cy="242.3"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Capa_1" /><g
+ id="g3"
+ style="fill:#{sdcol(icon)};fill-opacity:1"><g
+ id="g5"
+ style="fill:#{sdcol(icon)};fill-opacity:1"><path
+ d="M297.2,396.6c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5s1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5s3.5-5.3,3.5-8.5 s-1.3-6.3-3.5-8.5C303.5,397.9,300.4,396.6,297.2,396.6z"
+ id="path7"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M242.3,396.6c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12C254.3,402,248.9,396.6,242.3,396.6z"
+ id="path9"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M187.4,396.6c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5c0,3.1,1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5 s3.5-5.3,3.5-8.5s-1.3-6.3-3.5-8.5C193.6,397.9,190.5,396.6,187.4,396.6z"
+ id="path11"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M187.4,341.7c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12S194,341.7,187.4,341.7z"
+ id="path13"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M187.4,286.8c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5s1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5s3.5-5.3,3.5-8.5 s-1.3-6.3-3.5-8.5C193.6,288.1,190.5,286.8,187.4,286.8z"
+ id="path15"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M242.3,286.8c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12S248.9,286.8,242.3,286.8z"
+ id="path17"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M297.2,286.8c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5s1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5s3.5-5.3,3.5-8.5 s-1.3-6.3-3.5-8.5C303.5,288.1,300.4,286.8,297.2,286.8z"
+ id="path19"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M297.2,341.7c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12S303.8,341.7,297.2,341.7z"
+ id="path21"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /><path
+ d="M472.6,286.8h-42.9v-43.6c0-6.6-5.4-12-12-12H254.3v-33.4h42.9c6.6,0,12-5.4,12-12V76c0-6.6-5.4-12-12-12H187.4 c-6.6,0-12,5.4-12,12v109.8c0,6.6,5.4,12,12,12h42.9v33.4H66.9c-6.6,0-12,5.4-12,12v43.6H12c-6.6,0-12,5.4-12,12v109.8 c0,6.6,5.4,12,12,12h109.8c6.6,0,12-5.4,12-12V298.8c0-6.6-5.4-12-12-12H78.9v-31.6h326.8v31.6h-42.9c-6.6,0-12,5.4-12,12v109.8 c0,6.6,5.4,12,12,12h109.8c6.6,0,12-5.4,12-12V298.8C484.6,292.2,479.3,286.8,472.6,286.8z M109.8,310.8v85.8H24v-85.8H109.8z M199.4,173.8V88h85.8v85.8H199.4z M460.6,396.6h-85.8v-85.8h85.8V396.6z"
+ id="path23"
+ style="fill:#{sdcol(icon)};fill-opacity:1" /></g></g><g
+ id="g25" /><g
+ id="g27" /><g
+ id="g29" /><g
+ id="g31" /><g
+ id="g33" /><g
+ id="g35" /><g
+ id="g37" /><g
+ id="g39" /><g
+ id="g41" /><g
+ id="g43" /><g
+ id="g45" /><g
+ id="g47" /><g
+ id="g49" /><g
+ id="g51" /><g
+ id="g53" /></svg> \ No newline at end of file
diff --git a/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg
new file mode 100644
index 0000000..cb25723
--- /dev/null
+++ b/skins/estuary4vdr/svgtemplates/icons/ico_remotetimer_active.svg
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Generator: Adobe Illustrator 19.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ id="Capa_1"
+ x="0px"
+ y="0px"
+ viewBox="0 0 484.6 484.6"
+ style="enable-background:new 0 0 484.6 484.6;"
+ xml:space="preserve"
+ inkscape:version="0.91 r13725"
+ sodipodi:docname="ico_remotetimer.svg"><metadata
+ id="metadata59"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs57" /><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1920"
+ inkscape:window-height="1017"
+ id="namedview55"
+ showgrid="false"
+ inkscape:zoom="0.48699958"
+ inkscape:cx="-13.347034"
+ inkscape:cy="242.3"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Capa_1" /><g
+ id="g3"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1"><g
+ id="g5"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1"><path
+ d="M297.2,396.6c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5s1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5s3.5-5.3,3.5-8.5 s-1.3-6.3-3.5-8.5C303.5,397.9,300.4,396.6,297.2,396.6z"
+ id="path7"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M242.3,396.6c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12C254.3,402,248.9,396.6,242.3,396.6z"
+ id="path9"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M187.4,396.6c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5c0,3.1,1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5 s3.5-5.3,3.5-8.5s-1.3-6.3-3.5-8.5C193.6,397.9,190.5,396.6,187.4,396.6z"
+ id="path11"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M187.4,341.7c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12S194,341.7,187.4,341.7z"
+ id="path13"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M187.4,286.8c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5s1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5s3.5-5.3,3.5-8.5 s-1.3-6.3-3.5-8.5C193.6,288.1,190.5,286.8,187.4,286.8z"
+ id="path15"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M242.3,286.8c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12S248.9,286.8,242.3,286.8z"
+ id="path17"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M297.2,286.8c-3.2,0-6.3,1.3-8.5,3.5s-3.5,5.3-3.5,8.5s1.3,6.3,3.5,8.5s5.3,3.5,8.5,3.5s6.3-1.3,8.5-3.5s3.5-5.3,3.5-8.5 s-1.3-6.3-3.5-8.5C303.5,288.1,300.4,286.8,297.2,286.8z"
+ id="path19"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M297.2,341.7c-6.6,0-12,5.4-12,12s5.4,12,12,12s12-5.4,12-12S303.8,341.7,297.2,341.7z"
+ id="path21"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /><path
+ d="M472.6,286.8h-42.9v-43.6c0-6.6-5.4-12-12-12H254.3v-33.4h42.9c6.6,0,12-5.4,12-12V76c0-6.6-5.4-12-12-12H187.4 c-6.6,0-12,5.4-12,12v109.8c0,6.6,5.4,12,12,12h42.9v33.4H66.9c-6.6,0-12,5.4-12,12v43.6H12c-6.6,0-12,5.4-12,12v109.8 c0,6.6,5.4,12,12,12h109.8c6.6,0,12-5.4,12-12V298.8c0-6.6-5.4-12-12-12H78.9v-31.6h326.8v31.6h-42.9c-6.6,0-12,5.4-12,12v109.8 c0,6.6,5.4,12,12,12h109.8c6.6,0,12-5.4,12-12V298.8C484.6,292.2,479.3,286.8,472.6,286.8z M109.8,310.8v85.8H24v-85.8H109.8z M199.4,173.8V88h85.8v85.8H199.4z M460.6,396.6h-85.8v-85.8h85.8V396.6z"
+ id="path23"
+ style="fill:#{sdcol(iconactive)};fill-opacity:1" /></g></g><g
+ id="g25" /><g
+ id="g27" /><g
+ id="g29" /><g
+ id="g31" /><g
+ id="g33" /><g
+ id="g35" /><g
+ id="g37" /><g
+ id="g39" /><g
+ id="g41" /><g
+ id="g43" /><g
+ id="g45" /><g
+ id="g47" /><g
+ id="g49" /><g
+ id="g51" /><g
+ id="g53" /></svg> \ No newline at end of file
diff --git a/skins/estuary4vdr/xmlfiles/displaymenumain.xml b/skins/estuary4vdr/xmlfiles/displaymenumain.xml
index ef9b362..d6f0b67 100644
--- a/skins/estuary4vdr/xmlfiles/displaymenumain.xml
+++ b/skins/estuary4vdr/xmlfiles/displaymenumain.xml
@@ -38,7 +38,9 @@
<area condition="{numtimers}" x="2%" y="78%" width="28%" height="14%" layer="3">
<loop name="timers" x="5" y="3" orientation="vertical" columnwidth="{areawidth}" rowheight="{areaheight}/3" overflow="cut">
<drawimage cache="true" name="logo" imagetype="channellogo" path="{timers[channelid]}" width="{columnwidth}*0.15" height="{rowheight}*0.75" x="10" valign="center" />
- <drawtext x="{posx(logo)} + {width(logo)} + 10" y="0" font="{regular}" fontsize="{rowheight}*0.4" color="{fontdefault}" text="{timers[datetime]}" />
+ <drawtext name="datetime" x="{posx(logo)} + {width(logo)} + 10" y="0" font="{regular}" fontsize="{rowheight}*0.4" color="{fontdefault}" text="{timers[datetime]}" />
+ <drawimage condition="{timers[isremotetimer]}" name="remotetimericon" imagetype="icon" path="ico_remotetimer" width="{rowheight}*0.4" height="{rowheight}*0.4" x="{posx(datetime)} + {width(datetime)} + 10" y="0" />
+ <drawtext condition="{timers[isremotetimer]}" x="{posx(remotetimericon)} + {width(remotetimericon)} + 10" y="0" font="{regular}" fontsize="{rowheight}*0.4" color="{fontdefault}" text="{timers[remotehost]}" />
<drawtext x="{posx(logo)} + {width(logo)} + 10" y="{rowheight}*0.35" width="{columnwidth} - {posx(logo)} - {width(logo)} - 20" font="{regular}" fontsize="{rowheight}*0.6" color="{fontdefault}" text="{timers[title]}" />
</loop>
</area>
diff --git a/skins/estuary4vdr/xmlfiles/displaymenutimers.xml b/skins/estuary4vdr/xmlfiles/displaymenutimers.xml
index e25ff90..dada8c8 100644
--- a/skins/estuary4vdr/xmlfiles/displaymenutimers.xml
+++ b/skins/estuary4vdr/xmlfiles/displaymenutimers.xml
@@ -31,6 +31,8 @@
<drawimage condition="{current}++not{flagactive}++not{flagrecording}" imagetype="icon" path="ico_no_active" align="right" width="{areaheight}" height="{areaheight}" valign="center" />
<drawimage condition="not{current}++{flagrecording}" imagetype="icon" path="ico_recording" align="right" width="{areaheight}" height="{areaheight}" valign="center" />
<drawimage condition="{current}++{flagrecording}" imagetype="icon" path="ico_recording_active" align="right" width="{areaheight}" height="{areaheight}" valign="center" />
+ <drawimage condition="{current}++{isremote}" imagetype="icon" path="ico_remotetimer_active" x="{areawidth} - 2*{areaheight} - 10" width="{areaheight}" height="{areaheight}" valign="center" />
+ <drawimage condition="not{current}++{isremote}" imagetype="icon" path="ico_remotetimer" x="{areawidth} - 2*{areaheight} - 10" width="{areaheight}" height="{areaheight}" valign="center" />
</area>
</listelement>
<currentelement delay="100" fadetime="200">
diff --git a/skinskeleton/xmlfiles/displaymenumain.xml b/skinskeleton/xmlfiles/displaymenumain.xml
index eecf94a..a0a3284 100644
--- a/skinskeleton/xmlfiles/displaymenumain.xml
+++ b/skinskeleton/xmlfiles/displaymenumain.xml
@@ -15,7 +15,8 @@
{timers[channelnumber]} number of channel
{timers[channelid]} ChannelID of channel
{timers[channellogoexists]} true if channel logo exists
- {timers[isremotetimer]} true if timer is a remote timer from remotetimers plugin
+ {timers[isremotetimer]} true if timer is a remote timer from remotetimers or epg2vdr plugin
+ {timers[remotehost]} name of host on which timer is set. only for epg2vdr timers available
-->
<timers>
</timers>
diff --git a/skinskeleton/xmlfiles/displaymenutimers.xml b/skinskeleton/xmlfiles/displaymenutimers.xml
index 7889572..42aa090 100644
--- a/skinskeleton/xmlfiles/displaymenutimers.xml
+++ b/skinskeleton/xmlfiles/displaymenutimers.xml
@@ -23,6 +23,12 @@
{flagvps} true if timer uses VPS
{flagrecording} true if is recording currently
{flagpending} true if timer is pending
+ {isremote} true if timer is a epg2vdr remote timer
+ {vdrname} name of vdr on which epg2vdr timer is located
+ {isvdrrunning} true if vdr on which epg2vdr timer is located is running
+ {action} action of epg2vdr timer
+ {state} state of epg2vdr timer
+ {stateinfo} stateinfo of epg2vdr timer
-->
<listelement>
</listelement>