2014-09-27 09:25:14 +02:00
|
|
|
/*
|
|
|
|
* skindesigner.c: A plugin for the Video Disk Recorder
|
|
|
|
*
|
|
|
|
* See the README file for copyright information and how to reach the author.
|
|
|
|
*
|
|
|
|
* $Id$
|
|
|
|
*/
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <vdr/plugin.h>
|
|
|
|
|
|
|
|
#define DEFINE_CONFIG 1
|
|
|
|
#include "config.h"
|
|
|
|
#include "designer.h"
|
|
|
|
#include "setup.h"
|
2016-01-26 18:32:38 +01:00
|
|
|
#include "libskindesignerapi/skindesignerapi.h"
|
2014-09-27 09:25:14 +02:00
|
|
|
|
2016-03-13 16:06:17 +01:00
|
|
|
#if defined(APIVERSNUM) && APIVERSNUM < 20200
|
|
|
|
#error "VDR-2.2.0 API version or greater is required!"
|
2014-09-27 09:25:14 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2016-03-13 16:06:17 +01:00
|
|
|
static const char *VERSION = "0.9.0";
|
2015-01-27 17:46:21 +01:00
|
|
|
static const char *DESCRIPTION = trNOOP("Skin Designer");
|
2014-09-27 09:25:14 +02:00
|
|
|
|
2015-04-02 15:09:41 +02:00
|
|
|
class cPluginSkinDesigner : public cPlugin, public skindesignerapi::SkindesignerAPI {
|
2014-09-27 09:25:14 +02:00
|
|
|
private:
|
2015-04-03 09:18:26 +02:00
|
|
|
string libskindesignerApiVersion;
|
2016-01-26 18:32:38 +01:00
|
|
|
skindesignerapi::cPluginStructure *skinPreviewStruct;
|
2015-04-02 15:09:41 +02:00
|
|
|
protected:
|
|
|
|
bool ServiceRegisterPlugin(skindesignerapi::cPluginStructure *plugStructure);
|
|
|
|
skindesignerapi::ISDDisplayMenu *ServiceGetDisplayMenu(void);
|
2016-01-26 18:32:38 +01:00
|
|
|
skindesignerapi::ISkinDisplayPlugin *ServiceGetDisplayPlugin(int plugId);
|
2014-09-27 09:25:14 +02:00
|
|
|
public:
|
|
|
|
cPluginSkinDesigner(void);
|
|
|
|
virtual ~cPluginSkinDesigner();
|
|
|
|
virtual const char *Version(void) { return VERSION; }
|
2015-01-27 17:46:21 +01:00
|
|
|
virtual const char *Description(void) { return tr(DESCRIPTION); }
|
2014-09-27 09:25:14 +02:00
|
|
|
virtual const char *CommandLineHelp(void);
|
|
|
|
virtual bool ProcessArgs(int argc, char *argv[]);
|
|
|
|
virtual bool Initialize(void);
|
|
|
|
virtual bool Start(void);
|
|
|
|
virtual void Stop(void);
|
|
|
|
virtual void Housekeeping(void);
|
|
|
|
virtual void MainThreadHook(void);
|
|
|
|
virtual cString Active(void);
|
|
|
|
virtual time_t WakeupTime(void);
|
|
|
|
virtual const char *MainMenuEntry(void) {return NULL;}
|
|
|
|
virtual cOsdObject *MainMenuAction(void);
|
|
|
|
virtual cMenuSetupPage *SetupMenu(void);
|
|
|
|
virtual bool SetupParse(const char *Name, const char *Value);
|
|
|
|
virtual bool Service(const char *Id, void *Data = NULL);
|
|
|
|
virtual const char **SVDRPHelpPages(void);
|
|
|
|
virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode);
|
|
|
|
};
|
|
|
|
|
|
|
|
cPluginSkinDesigner::cPluginSkinDesigner(void) {
|
2015-04-03 09:18:26 +02:00
|
|
|
libskindesignerApiVersion = "undefined";
|
2015-07-17 17:37:16 +02:00
|
|
|
config.SetVersion(VERSION);
|
2016-01-26 18:32:38 +01:00
|
|
|
skinPreviewStruct = NULL;
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cPluginSkinDesigner::~cPluginSkinDesigner() {
|
2016-01-26 18:32:38 +01:00
|
|
|
delete skinPreviewStruct;
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const char *cPluginSkinDesigner::CommandLineHelp(void) {
|
|
|
|
return
|
2015-05-22 13:34:23 +02:00
|
|
|
" -s <SKINPATH>, --skinpath=<SKINPATH> Set directory where xml skins are stored by Package Manager\n"
|
|
|
|
" -i <INSTALLERPATH>, --installerpath=<INSTALLERPATH> Set directory where xml skins are stored by Installer\n"
|
2014-10-03 15:54:23 +02:00
|
|
|
" -l <LOGOPATH>, --logopath=<LOGOPATH> Set directory where a common logo set for all skins is stored\n"
|
2014-09-27 09:25:14 +02:00
|
|
|
" -e <EPGIMAGESPATH>, --epgimages=<IMAGESPATH> Set directory where epgimages are stored\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSkinDesigner::ProcessArgs(int argc, char *argv[]) {
|
|
|
|
// Implement command line argument processing here if applicable.
|
|
|
|
static const struct option long_options[] = {
|
|
|
|
{ "epgimages", required_argument, NULL, 'e' },
|
2014-10-03 15:54:23 +02:00
|
|
|
{ "logopath", required_argument, NULL, 'l' },
|
2014-09-27 09:25:14 +02:00
|
|
|
{ "skinpath", required_argument, NULL, 's' },
|
2015-05-22 13:34:23 +02:00
|
|
|
{ "installerpath", required_argument, NULL, 'i' },
|
2014-09-27 09:25:14 +02:00
|
|
|
{ 0, 0, 0, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
int c;
|
2015-05-22 13:34:23 +02:00
|
|
|
while ((c = getopt_long(argc, argv, "e:s:l:i:", long_options, NULL)) != -1) {
|
2014-09-27 09:25:14 +02:00
|
|
|
switch (c) {
|
|
|
|
case 'e':
|
|
|
|
config.SetEpgImagePath(cString(optarg));
|
|
|
|
break;
|
2014-10-03 15:54:23 +02:00
|
|
|
case 'l':
|
|
|
|
config.SetLogoPath(cString(optarg));
|
|
|
|
break;
|
2014-09-27 09:25:14 +02:00
|
|
|
case 's':
|
|
|
|
config.SetSkinPath(cString(optarg));
|
|
|
|
break;
|
2015-05-22 13:34:23 +02:00
|
|
|
case 'i':
|
|
|
|
config.SetInstallerSkinPath(cString(optarg));
|
|
|
|
break;
|
2014-09-27 09:25:14 +02:00
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSkinDesigner::Initialize(void) {
|
2016-02-06 10:01:12 +01:00
|
|
|
plgManager = new cSDPluginManager();
|
2014-09-27 09:25:14 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSkinDesigner::Start(void) {
|
2014-11-12 16:58:01 +01:00
|
|
|
cXmlParser::InitLibXML();
|
2014-11-23 13:07:43 +01:00
|
|
|
cImageImporterSVG::InitLibRSVG();
|
2014-10-03 15:54:23 +02:00
|
|
|
bool trueColorAvailable = true;
|
2015-01-20 09:29:16 +01:00
|
|
|
|
2014-09-27 09:25:14 +02:00
|
|
|
if (!cOsdProvider::SupportsTrueColor()) {
|
2014-09-28 10:47:54 +02:00
|
|
|
esyslog("skindesigner: No TrueColor OSD found! Using default Skin LCARS!");
|
2014-10-03 15:54:23 +02:00
|
|
|
trueColorAvailable = false;
|
2014-09-27 09:25:14 +02:00
|
|
|
} else
|
2014-09-28 10:47:54 +02:00
|
|
|
dsyslog("skindesigner: TrueColor OSD found");
|
2015-04-03 09:18:26 +02:00
|
|
|
|
|
|
|
libskindesignerApiVersion = LIBSKINDESIGNERAPIVERSION;
|
|
|
|
dsyslog("skindesigner: using libskindesigner API Version %s", libskindesignerApiVersion.c_str());
|
|
|
|
|
2016-01-26 18:32:38 +01:00
|
|
|
skinPreviewStruct = new skindesignerapi::cPluginStructure();
|
|
|
|
skinPreviewStruct->name = "setup";
|
|
|
|
skinPreviewStruct->libskindesignerAPIVersion = LIBSKINDESIGNERAPIVERSION;
|
|
|
|
skindesignerapi::cTokenContainer *tkSkinPreview = new skindesignerapi::cTokenContainer();
|
|
|
|
cSkindesignerSkinPreview::DefineTokens(tkSkinPreview);
|
|
|
|
skinPreviewStruct->RegisterMenu(0, skindesignerapi::mtText, "skinpreview.xml", tkSkinPreview);
|
|
|
|
if (RegisterPlugin(skinPreviewStruct)) {
|
|
|
|
dsyslog("skindesigner: skinsetup template successfully registered at skindesigner, id %d", skinPreviewStruct->id);
|
|
|
|
}
|
2015-05-30 16:43:59 +02:00
|
|
|
|
2015-01-21 18:33:19 +01:00
|
|
|
config.SetOsdLanguage();
|
2014-10-03 15:54:23 +02:00
|
|
|
config.SetPathes();
|
|
|
|
config.ReadSkins();
|
|
|
|
config.InitSkinIterator();
|
|
|
|
string skin = "";
|
2015-05-30 16:43:59 +02:00
|
|
|
bool skinAvailable = false;
|
2014-10-03 15:54:23 +02:00
|
|
|
while (config.GetSkin(skin)) {
|
2015-01-19 09:23:15 +01:00
|
|
|
config.ReadSkinSetup(skin);
|
2016-02-14 15:06:30 +01:00
|
|
|
cTheme *theme = new cTheme();
|
|
|
|
config.StoreTheme(theme);
|
|
|
|
cSkinDesigner *newSkin = new cSkinDesigner(skin, theme);
|
2015-05-30 16:43:59 +02:00
|
|
|
config.AddSkin(newSkin);
|
|
|
|
skinAvailable = true;
|
2014-10-03 15:54:23 +02:00
|
|
|
if (!trueColorAvailable) {
|
|
|
|
newSkin->ActivateBackupSkin();
|
|
|
|
}
|
|
|
|
}
|
2015-01-20 09:29:16 +01:00
|
|
|
config.TranslateSetup();
|
2015-01-20 14:26:28 +01:00
|
|
|
config.SetSkinSetupParameters();
|
2015-05-22 13:34:23 +02:00
|
|
|
config.ReadSkinRepos();
|
2015-01-20 09:29:16 +01:00
|
|
|
|
2015-05-30 16:43:59 +02:00
|
|
|
if (!skinAvailable) {
|
2014-10-04 10:10:04 +02:00
|
|
|
esyslog("skindesigner: no skins found! Using default Skin LCARS!");
|
|
|
|
}
|
2014-10-03 15:54:23 +02:00
|
|
|
return true;
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void cPluginSkinDesigner::Stop(void) {
|
|
|
|
delete imgCache;
|
|
|
|
delete fontManager;
|
2016-01-26 18:32:38 +01:00
|
|
|
delete plgManager;
|
2014-11-12 16:58:01 +01:00
|
|
|
cXmlParser::CleanupLibXML();
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void cPluginSkinDesigner::Housekeeping(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
void cPluginSkinDesigner::MainThreadHook(void) {
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cPluginSkinDesigner::Active(void) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
time_t cPluginSkinDesigner::WakeupTime(void) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
cOsdObject *cPluginSkinDesigner::MainMenuAction(void) {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cMenuSetupPage *cPluginSkinDesigner::SetupMenu(void) {
|
2016-01-26 18:32:38 +01:00
|
|
|
return new cSkinDesignerSetup(skinPreviewStruct);
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSkinDesigner::SetupParse(const char *Name, const char *Value) {
|
|
|
|
return config.SetupParse(Name, Value);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cPluginSkinDesigner::Service(const char *Id, void *Data) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char **cPluginSkinDesigner::SVDRPHelpPages(void) {
|
|
|
|
static const char *HelpPages[] = {
|
|
|
|
"RELD\n"
|
|
|
|
" force reload of templates and caches",
|
2016-01-31 16:32:41 +01:00
|
|
|
"DLIC\n"
|
|
|
|
" delete image cache",
|
2016-01-26 18:32:38 +01:00
|
|
|
"SCIT\n"
|
|
|
|
" Set custom Integer Token key = value",
|
|
|
|
"SCST\n"
|
|
|
|
" Set custom String Token key = value",
|
2014-10-11 16:31:39 +02:00
|
|
|
"LCTK\n"
|
|
|
|
" List custom Tokens",
|
2014-09-27 09:25:14 +02:00
|
|
|
"LSTF\n"
|
|
|
|
" List available Fonts",
|
|
|
|
0
|
|
|
|
};
|
|
|
|
return HelpPages;
|
|
|
|
}
|
|
|
|
|
|
|
|
cString cPluginSkinDesigner::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) {
|
2014-10-03 15:54:23 +02:00
|
|
|
|
|
|
|
cSkinDesigner *activeSkin = NULL;
|
2015-05-30 16:43:59 +02:00
|
|
|
cSkinDesigner *availableSkin = NULL;
|
|
|
|
config.InitSkinRefsIterator();
|
|
|
|
while (availableSkin = config.GetNextSkinRef()) {
|
2014-10-03 15:54:23 +02:00
|
|
|
string activeSkinName = Setup.OSDSkin;
|
2015-05-30 16:43:59 +02:00
|
|
|
string currentSkinName = availableSkin->Description();
|
2014-10-03 15:54:23 +02:00
|
|
|
if (!currentSkinName.compare(activeSkinName)) {
|
2015-05-30 16:43:59 +02:00
|
|
|
activeSkin = availableSkin;
|
2014-10-03 15:54:23 +02:00
|
|
|
break;
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
2014-10-03 15:54:23 +02:00
|
|
|
}
|
|
|
|
|
2014-10-11 16:31:39 +02:00
|
|
|
if (!activeSkin) {
|
|
|
|
ReplyCode = 550;
|
2016-02-21 23:31:36 +01:00
|
|
|
return "SKINDESIGNER not active.";
|
2014-10-11 16:31:39 +02:00
|
|
|
}
|
2014-10-03 15:54:23 +02:00
|
|
|
|
|
|
|
if (strcasecmp(Command, "RELD") == 0) {
|
2015-01-20 09:29:16 +01:00
|
|
|
config.ClearSkinSetups();
|
|
|
|
config.InitSkinIterator();
|
|
|
|
string skin = "";
|
|
|
|
while (config.GetSkin(skin)) {
|
|
|
|
config.ReadSkinSetup(skin);
|
|
|
|
}
|
|
|
|
config.TranslateSetup();
|
2015-01-20 14:26:28 +01:00
|
|
|
config.SetSkinSetupParameters();
|
2014-10-03 15:54:23 +02:00
|
|
|
activeSkin->Reload();
|
2014-10-11 16:31:39 +02:00
|
|
|
ReplyCode = 250;
|
2014-10-03 15:54:23 +02:00
|
|
|
return "SKINDESIGNER reload of templates and caches forced.";
|
2016-01-31 16:32:41 +01:00
|
|
|
} else if (strcasecmp(Command, "DLIC") == 0) {
|
|
|
|
if (imgCache)
|
|
|
|
delete imgCache;
|
|
|
|
imgCache = new cImageCache();
|
|
|
|
imgCache->SetPathes();
|
|
|
|
ReplyCode = 250;
|
|
|
|
return "SKINDESIGNER Image Cache deleted.";
|
2014-09-27 09:25:14 +02:00
|
|
|
} else if (strcasecmp(Command, "LSTF") == 0) {
|
2014-10-03 15:54:23 +02:00
|
|
|
activeSkin->ListAvailableFonts();
|
2014-10-11 16:31:39 +02:00
|
|
|
ReplyCode = 250;
|
2014-10-03 15:54:23 +02:00
|
|
|
return "SKINDESIGNER available fonts listed in syslog.";
|
2016-01-26 18:32:38 +01:00
|
|
|
} else if (strcasecmp(Command, "SCIT") == 0) {
|
2014-10-11 16:31:39 +02:00
|
|
|
if (!Option) {
|
|
|
|
ReplyCode = 501;
|
2016-01-26 18:32:38 +01:00
|
|
|
return "SKINDESIGNER SCIK Error: no Token name = value set";
|
2014-10-11 16:31:39 +02:00
|
|
|
}
|
2016-01-26 18:32:38 +01:00
|
|
|
bool optionOk = activeSkin->SetCustomIntToken(Option);
|
2014-10-11 16:31:39 +02:00
|
|
|
if (optionOk) {
|
|
|
|
ReplyCode = 250;
|
2016-01-26 18:32:38 +01:00
|
|
|
return cString::sprintf("SKINDESIGNER Set custom Int Token %s", Option);
|
2014-10-11 16:31:39 +02:00
|
|
|
} else {
|
|
|
|
ReplyCode = 501;
|
2016-01-26 18:32:38 +01:00
|
|
|
return cString::sprintf("SKINDESIGNER Invalid custom Int Token %s", Option);
|
|
|
|
}
|
|
|
|
} else if (strcasecmp(Command, "SCST") == 0) {
|
|
|
|
if (!Option) {
|
|
|
|
ReplyCode = 501;
|
|
|
|
return "SKINDESIGNER SCSK Error: no Token name = value set";
|
|
|
|
}
|
|
|
|
bool optionOk = activeSkin->SetCustomStringToken(Option);
|
|
|
|
if (optionOk) {
|
|
|
|
ReplyCode = 250;
|
|
|
|
return cString::sprintf("SKINDESIGNER Set custom String Token %s", Option);
|
|
|
|
} else {
|
|
|
|
ReplyCode = 501;
|
|
|
|
return cString::sprintf("SKINDESIGNER Invalid custom String Token %s", Option);
|
2014-10-11 16:31:39 +02:00
|
|
|
}
|
|
|
|
} else if (strcasecmp(Command, "LCTK") == 0) {
|
|
|
|
activeSkin->ListCustomTokens();
|
|
|
|
ReplyCode = 250;
|
|
|
|
return "SKINDESIGNER Custom Tokens listed in Log";
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
2014-10-11 16:31:39 +02:00
|
|
|
ReplyCode = 502;
|
2016-02-21 23:31:36 +01:00
|
|
|
return "SKINDESIGNER invalid SVDRP command.";
|
2014-09-27 09:25:14 +02:00
|
|
|
}
|
|
|
|
|
2016-01-26 18:32:38 +01:00
|
|
|
|
2015-04-02 15:09:41 +02:00
|
|
|
bool cPluginSkinDesigner::ServiceRegisterPlugin(skindesignerapi::cPluginStructure *plugStructure) {
|
2016-01-26 18:32:38 +01:00
|
|
|
if (plugStructure->menus.size() < 1 && plugStructure->rootview.size() < 1) {
|
2015-04-02 15:09:41 +02:00
|
|
|
esyslog("skindesigner: error - plugin without menus or views registered");
|
|
|
|
return false;
|
|
|
|
}
|
2016-01-26 18:32:38 +01:00
|
|
|
//basic plugin interface
|
2015-04-02 15:09:41 +02:00
|
|
|
if (plugStructure->menus.size() > 0)
|
2016-01-26 18:32:38 +01:00
|
|
|
plgManager->RegisterBasicPlugin(plugStructure);
|
|
|
|
//advanced plugin interface
|
|
|
|
if (plugStructure->rootview.size() > 0)
|
|
|
|
plgManager->RegisterAdvancedPlugin(plugStructure);
|
2015-04-02 15:09:41 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
skindesignerapi::ISDDisplayMenu *cPluginSkinDesigner::ServiceGetDisplayMenu(void) {
|
|
|
|
cSkin *current = Skins.Current();
|
2015-05-30 16:43:59 +02:00
|
|
|
cSkinDesigner *availableSkin = NULL;
|
|
|
|
config.InitSkinRefsIterator();
|
|
|
|
while (availableSkin = config.GetNextSkinRef()) {
|
|
|
|
if (availableSkin == current) {
|
|
|
|
cSDDisplayMenu *displayMenu = availableSkin->GetDisplayMenu();
|
2015-04-02 15:09:41 +02:00
|
|
|
if (displayMenu) {
|
|
|
|
return displayMenu;
|
|
|
|
} else {
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2016-01-26 18:32:38 +01:00
|
|
|
skindesignerapi::ISkinDisplayPlugin *cPluginSkinDesigner::ServiceGetDisplayPlugin(int plugId) {
|
2015-04-02 15:09:41 +02:00
|
|
|
cSkin *current = Skins.Current();
|
2015-05-30 16:43:59 +02:00
|
|
|
cSkinDesigner *availableSkin = NULL;
|
|
|
|
config.InitSkinRefsIterator();
|
|
|
|
while (availableSkin = config.GetNextSkinRef()) {
|
|
|
|
if (availableSkin == current) {
|
2016-01-26 18:32:38 +01:00
|
|
|
return availableSkin->GetDisplayPlugin(plugId);
|
2015-04-02 15:09:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-09-27 09:25:14 +02:00
|
|
|
VDRPLUGINCREATOR(cPluginSkinDesigner); // Don't touch this!
|