1
0
mirror of https://github.com/VDR4Arch/vdr.git synced 2023-10-10 13:36:52 +02:00

Improved implementation of setup menus for plugins

This commit is contained in:
Klaus Schmidinger 2002-05-11 13:44:58 +02:00
parent 0fac78954c
commit 51eb880da0
7 changed files with 309 additions and 155 deletions

View File

@ -15,7 +15,10 @@ VDR code (and all the problems of correlating various patches).
This document describes the "outside" interface of the plugin system. This document describes the "outside" interface of the plugin system.
It handles everything necessary for a plugin to get hooked into the core It handles everything necessary for a plugin to get hooked into the core
VDR program and present itself to the user. VDR program and present itself to the user.
<p>
<!--X1.1.1--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
Important modifications introduced in version 1.1.1 are marked like this.
<!--X1.1.1--></td></tr></table>
<!--<p>TODO: Link to the document about VDR base classes to use when implementing actual functionality (yet to be written).--> <!--<p>TODO: Link to the document about VDR base classes to use when implementing actual functionality (yet to be written).-->
<hr><h2>Quick start</h2> <hr><h2>Quick start</h2>
@ -25,12 +28,12 @@ VDR program and present itself to the user.
Actually you should read this entire document before starting to work with VDR plugins, Actually you should read this entire document before starting to work with VDR plugins,
but you probably want to see something happening right away <tt>;-)</tt> but you probably want to see something happening right away <tt>;-)</tt>
<p> <p>
So, for a quick demonstration of the plugin system, there is a demo plugin called So, for a quick demonstration of the plugin system, there is a sample plugin called
"hello" that comes with the VDR source. To test drive this one, do the following: "hello" that comes with the VDR source. To test drive this one, do the following:
<ul> <ul>
<li>change into the VDR source directory <li>change into the VDR source directory
<li><b><tt>make</tt></b> the VDR program with your usual <tt>REMOTE=...</tt> (and maybe other) options <li><b><tt>make</tt></b> the VDR program with your usual <tt>REMOTE=...</tt> (and maybe other) options
<li>do <b><tt>make plugins</tt></b> to build the demo plugin <li>do <b><tt>make plugins</tt></b> to build the plugin
<li>run VDR with <b><tt>vdr -V</tt></b> to see the version information <li>run VDR with <b><tt>vdr -V</tt></b> to see the version information
<li>run VDR with <b><tt>vdr -h</tt></b> to see the command line options <li>run VDR with <b><tt>vdr -h</tt></b> to see the command line options
<li>run VDR with <b><tt>vdr -Phello</tt></b> <li>run VDR with <b><tt>vdr -Phello</tt></b>
@ -74,16 +77,14 @@ is used:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
VDR/PLUGINS/src VDR/PLUGINS/src
VDR/PLUGINS/src/demo
VDR/PLUGINS/src/hello VDR/PLUGINS/src/hello
VDR/PLUGINS/lib VDR/PLUGINS/lib
VDR/PLUGINS/lib/libvdr-demo.so.1.1.0
VDR/PLUGINS/lib/libvdr-hello.so.1.1.0 VDR/PLUGINS/lib/libvdr-hello.so.1.1.0
</pre></td></tr></table><p> </pre></td></tr></table><p>
The <tt>src</tt> directory contains one subdirectory for each plugin, which carries The <tt>src</tt> directory contains one subdirectory for each plugin, which carries
the name of that plugin (in the above example that would be <tt>demo</tt> and the name of that plugin (in the above example that would be <tt>hello</tt>).
<tt>hello</tt>, respectively). What's inside the individual source directory of a What's inside the individual source directory of a
plugin is entirely up to the author of that plugin. The only prerequisites are plugin is entirely up to the author of that plugin. The only prerequisites are
that there is a <tt>Makefile</tt> that provides the targets <tt>all</tt> and that there is a <tt>Makefile</tt> that provides the targets <tt>all</tt> and
<tt>clean</tt>, and that a call to <tt>make all</tt> actually produces a dynamically <tt>clean</tt>, and that a call to <tt>make all</tt> actually produces a dynamically
@ -93,7 +94,7 @@ The <tt>lib</tt> directory contains the dynamically loadable libraries of all
available plugins. Note that the names of these files are created by concatenating available plugins. Note that the names of these files are created by concatenating
<p> <p>
<table border=2> <table border=2>
<tr><td align=center><b><tt>libvdr-</tt></b></td><td align=center><b><tt>demo</tt></b></td><td align=center><b><tt>.so.</tt></b></td><td align=center><b><tt>1.1.0</tt></b></td></tr> <tr><td align=center><b><tt>libvdr-</tt></b></td><td align=center><b><tt>hello</tt></b></td><td align=center><b><tt>.so.</tt></b></td><td align=center><b><tt>1.1.0</tt></b></td></tr>
<tr><td align=center><font size=-1>VDR plugin<br>library prefix</font></td><td align=center><font size=-1>name of<br>the plugin</font></td><td align=center><font size=-1>shared object<br>indicator</font></td><td align=center><font size=-1>VDR version number<br>this plugin was<br>compiled for</font></td></tr> <tr><td align=center><font size=-1>VDR plugin<br>library prefix</font></td><td align=center><font size=-1>name of<br>the plugin</font></td><td align=center><font size=-1>shared object<br>indicator</font></td><td align=center><font size=-1>VDR version number<br>this plugin was<br>compiled for</font></td></tr>
</table> </table>
<p> <p>
@ -109,25 +110,25 @@ each of these directories.
If you download a plugin <a href="#Building the distribution package">package</a> If you download a plugin <a href="#Building the distribution package">package</a>
from the web, it will typically have a name like from the web, it will typically have a name like
<p> <p>
<tt>vdr-demo-0.0.1.tgz</tt> <tt>vdr-hello-0.0.1.tgz</tt>
<p> <p>
and will unpack into a directory named and will unpack into a directory named
<p> <p>
<tt>vdr-demo-0.0.1</tt> <tt>vdr-hello-0.0.1</tt>
<p> <p>
To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>Makefile</tt> To use the <tt>plugins</tt> and <tt>plugins-clean</tt> targets from the VDR <tt>Makefile</tt>
you need to unpack such an archive into the <tt>VDR/PLUGINS/src</tt> directory and you need to unpack such an archive into the <tt>VDR/PLUGINS/src</tt> directory and
create a symbolic link with the basic plugin name, as in create a symbolic link with the basic plugin name, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
ln -s vdr-demo-0.0.1 demo ln -s vdr-hello-0.0.1 hello
</pre></td></tr></table><p> </pre></td></tr></table><p>
Since the VDR <tt>Makefile</tt> only searches for directories with names consisting Since the VDR <tt>Makefile</tt> only searches for directories with names consisting
of only lowercase characters and digits, it will only follow the symbolic links, which of only lowercase characters and digits, it will only follow the symbolic links, which
should lead to the current version of the plugin you want to use. This way you can should lead to the current version of the plugin you want to use. This way you can
have several different versions of a plugin source (like <tt>vdr-demo-0.0.1</tt> and have several different versions of a plugin source (like <tt>vdr-hello-0.0.1</tt> and
<tt>vdr-demo-0.0.2</tt>) and define which one to actually use through the symbolic link. <tt>vdr-hello-0.0.2</tt>) and define which one to actually use through the symbolic link.
<a name="Initializing a new plugin directory"><hr><h2>Initializing a new plugin directory</h2> <a name="Initializing a new plugin directory"><hr><h2>Initializing a new plugin directory</h2>
@ -174,7 +175,7 @@ If your plugin shall not be accessible through VDR's main menu, simply remove
At the end of the plugin's source file you will find a line that looks like this: At the end of the plugin's source file you will find a line that looks like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
VDRPLUGINCREATOR(cPluginDemo); VDRPLUGINCREATOR(cPluginHello);
</pre></td></tr></table><p> </pre></td></tr></table><p>
This is the "magic" hook that allows VDR to actually load the plugin into This is the "magic" hook that allows VDR to actually load the plugin into
@ -230,9 +231,7 @@ Here's an example:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
static const char *VERSION = "0.0.1"; static const char *VERSION = "0.0.1";
... const char *cPluginHello::Version(void)
const char *cPluginDemo::Version(void)
{ {
return VERSION; return VERSION;
} }
@ -265,15 +264,20 @@ In order to tell the user what exactly a plugin does, it must implement the func
virtual const char *Description(void) = 0; virtual const char *Description(void) = 0;
</pre></td></tr></table><p> </pre></td></tr></table><p>
which returns a short, one line description of the plugin's purpose. which returns a short, one line description of the plugin's purpose:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
static const char *DESCRIPTION = "A friendly greeting";
virtual const char *Description(void) virtual const char *Description(void)
{ {
return "A simple demo plugin"; return tr(DESCRIPTION);
} }
</pre></td></tr></table><p> </pre></td></tr></table><p>
Note the <tt>tr()</tt> around the <tt>DESCRIPTION</tt>, which allows the description
to be <a href="#Internationalization">internationalized</a>.
<hr><h2>Command line arguments</h2> <hr><h2>Command line arguments</h2>
<center><i><b>Taking orders</b></i></center><p> <center><i><b>Taking orders</b></i></center><p>
@ -300,20 +304,21 @@ will survive the entire lifetime of the plugin, so it is safe to store pointers
these values inside the plugin. Here's an example: these values inside the plugin. Here's an example:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
bool cPluginDemo::ProcessArgs(int argc, char *argv[]) bool cPluginHello::ProcessArgs(int argc, char *argv[])
{ {
// Implement command line argument processing here if applicable.
static struct option long_options[] = { static struct option long_options[] = {
{ "aaa", required_argument, NULL, 'a' }, { "aaa", required_argument, NULL, 'a' },
{ "bbb", no_argument, NULL, 'b' }, { "bbb", no_argument, NULL, 'b' },
{ NULL } { NULL }
}; };
int c; int c;
while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) { while ((c = getopt_long(argc, argv, "a:b", long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'a': fprintf(stderr, "option -a = %s\n", optarg); case 'a': option_a = optarg;
break; break;
case 'b': fprintf(stderr, "option -b\n"); case 'b': option_b = true;
break; break;
default: return false; default: return false;
} }
@ -342,8 +347,9 @@ The returned string should contain the command line help for this plugin, format
in the same way as done by VDR itself: in the same way as done by VDR itself:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
const char *cPluginDemo::CommandLineHelp(void) const char *cPluginHello::CommandLineHelp(void)
{ {
// Return a string that describes all known command line options.
return " -a ABC, --aaa=ABC do something nice with ABC\n" return " -a ABC, --aaa=ABC do something nice with ABC\n"
" -b, --bbb activate 'plan B'\n"; " -b, --bbb activate 'plan B'\n";
} }
@ -392,9 +398,11 @@ this plugin will not have an item in the main menu. Here's an example of a
plugin that will have a main menu item: plugin that will have a main menu item:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
const char *cPluginDemo::MainMenuEntry(void) static const char *MAINMENUENTRY = "Hello";
const char *cPluginHello::MainMenuEntry(void)
{ {
return "Demo"; return tr(MAINMENUENTRY);
} }
</pre></td></tr></table><p> </pre></td></tr></table><p>
@ -440,7 +448,7 @@ virtual cMenuSetupPage *SetupMenu(void);
virtual bool SetupParse(const char *Name, const char *Value); virtual bool SetupParse(const char *Name, const char *Value);
</pre></td></tr></table><p> </pre></td></tr></table><p>
The <tt>SetupMenu()</tt> function shall return the plugin's "Setup" menu The <tt>SetupMenu()</tt> function shall return the plugin's <a href="#The Setup menu"><i>Setup</i> menu</a>
page, where the user can adjust all the parameters known to this plugin. page, where the user can adjust all the parameters known to this plugin.
<p> <p>
<tt>SetupParse()</tt> will be called for each parameter the plugin has <tt>SetupParse()</tt> will be called for each parameter the plugin has
@ -448,13 +456,30 @@ previously stored in the global setup data (see below). It shall return
<i>true</i> if the parameter was parsed correctly, <i>false</i> in case of <i>true</i> if the parameter was parsed correctly, <i>false</i> in case of
an error. If <i>false</i> is returned, an error message will be written to an error. If <i>false</i> is returned, an error message will be written to
the log file (and program execution will continue). the log file (and program execution will continue).
<!--X1.1.1--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
A possible implementation of <tt>SetupParse()</tt> could look like this:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
bool cPluginHello::SetupParse(const char *Name, const char *Value)
{
// Parse your own setup parameters and store their values.
if (!strcasecmp(Name, "GreetingTime")) GreetingTime = atoi(Value);
else if (!strcasecmp(Name, "UseAlternateGreeting")) UseAlternateGreeting = atoi(Value);
else
return false;
return true;
</pre></td></tr></table><p>
It is important to make sure that the parameter names are exactly the same as
used in the <a href="#The Setup menu"><i>Setup</i> menu</a>'s <tt>Store()</tt> function.
<!--X1.1.1--></td></tr></table>
<p> <p>
The plugin's setup parameters are stored in the same file as VDR's parameters. The plugin's setup parameters are stored in the same file as VDR's parameters.
In order to allow each plugin (and VDR itself) to have its own set of parameters, In order to allow each plugin (and VDR itself) to have its own set of parameters,
the <tt>Name</tt> of each parameter will be preceeded with the plugin's the <tt>Name</tt> of each parameter will be preceeded with the plugin's
name, as in name, as in
<p> <p>
<tt>demo.SomeParameter = 123</tt> <tt>hello.GreetingTime = 3</tt>
<p> <p>
The prefix will be handled by the core VDR setup code, so the individual The prefix will be handled by the core VDR setup code, so the individual
plugins need not worry about this. plugins need not worry about this.
@ -465,8 +490,8 @@ To store its values in the global setup, a plugin has to call the function
void SetupStore(const char *Name, <i>type</i> Value); void SetupStore(const char *Name, <i>type</i> Value);
</pre></td></tr></table><p> </pre></td></tr></table><p>
where <tt>Name</tt> is the name of the parameter (<tt>"SomeParameter"</tt> in the above where <tt>Name</tt> is the name of the parameter (<tt>"GreetingTime"</tt> in the above
example, without the prefix <tt>"demo."</tt>) and <tt>Value</tt> is a simple data type (like example, without the prefix <tt>"hello."</tt>) and <tt>Value</tt> is a simple data type (like
<tt>char&nbsp;*</tt>, <tt>int</tt> etc). <tt>char&nbsp;*</tt>, <tt>int</tt> etc).
Note that this is not a function that the individual plugin class needs to implement! Note that this is not a function that the individual plugin class needs to implement!
<tt>SetupStore()</tt> is a non-virtual member function of the <tt>cPlugin</tt> class. <tt>SetupStore()</tt> is a non-virtual member function of the <tt>cPlugin</tt> class.
@ -474,7 +499,7 @@ Note that this is not a function that the individual plugin class needs to imple
To remove a parameter from the setup data, call <tt>SetupStore()</tt> with the appropriate To remove a parameter from the setup data, call <tt>SetupStore()</tt> with the appropriate
name and without any value, as in name and without any value, as in
<p> <p>
<tt>SetupStore("SomeParameter");</tt> <tt>SetupStore("GreetingTime");</tt>
<p> <p>
The VDR menu "Setup/Plugins" will list all loaded plugins with their name, The VDR menu "Setup/Plugins" will list all loaded plugins with their name,
version number and description. Selecting an item in this list will bring up version number and description. Selecting an item in this list will bring up
@ -486,6 +511,66 @@ needs setup parameters that are not directly user adjustable. It can use
<tt>SetupStore()</tt> and <tt>SetupParse()</tt> without presenting these <tt>SetupStore()</tt> and <tt>SetupParse()</tt> without presenting these
parameters to the user. parameters to the user.
<!--X1.1.1--><table width=100%><tr><td bgcolor=red>&nbsp;</td><td width=100%>
<a name="The Setup menu"><hr><h2>The Setup menu</h2>
<center><i><b>Have it your way!</b></i></center><p>
To implement a <i>Setup</i> menu, a plugin needs to derive a class from
<tt>cMenuSetupPage</tt> and implement its constructor and the pure virtual
<tt>Store()</tt> member function:
<p><table><tr><td bgcolor=#F0F0F0><pre><br>
int GreetingTime = 3;
int UseAlternateGreeting = false;
class cMenuSetupHello : public cMenuSetupPage {
private:
int newGreetingTime;
int newUseAlternateGreeting;
protected:
virtual void Store(void);
public:
cMenuSetupHello(void);
};
cMenuSetupHello::cMenuSetupHello(void)
{
newGreetingTime = GreetingTime;
newUseAlternateGreeting = UseAlternateGreeting;
Add(new cMenuEditIntItem( tr("Greeting time (s)"), &amp;newGreetingTime));
Add(new cMenuEditBoolItem(tr("Use alternate greeting"), &amp;newUseAlternateGreeting));
}
void cMenuSetupHello::Store(void)
{
SetupStore("GreetingTime", GreetingTime = newGreetingTime);
SetupStore("UseAlternateGreeting", UseAlternateGreeting = newUseAlternateGreeting);
}
</pre></td></tr></table><p>
In this example we have two global setup parameters (<tt>GreetingTime</tt> and <tt>UseAlternateGreeting</tt>).
The constructor initializes two private members with the values of these parameters, so
that the <i>Setup</i> menu can work with temporary copies (in order to discard any changes
if the user doesn't confirm them by pressing the "Ok" button).
After this the constructor adds the appropriate menu items, using internationalized texts
and the addresses of the temporary variables. That's all there is to inizialize a <i>Setup</i>
menu - the rest will be done by the core VDR code.
<p>
Once the user has pressed the "Ok" button to confirm the changes, the <tt>Store()</tt> function will
be called, in which all setup parameters must be actually stored in VDR's global setup data.
This is done by calling the <tt>SetupStore()</tt> function for each of the parameters.
The <i>Name</i> string given here will be used to identify the parameter in VDR's
<tt>setup.conf</tt> file, and will be automatically prepended with the plugin's name.
<p>
Note that in this small example the new values of the parameters are copied into the
global variables within each <tt>SetupStore()</tt> call. This is not mandatory, however.
You can first assign the temporary values to the global variables and then do the
<tt>SetupStore()</tt> calls, or you can define a class or struct that contains all
your setup parameters and use that one to copy all parameters with one single statement
(like VDR does with its cSetup class).
<!--X1.1.1--></td></tr></table>
<a name="Internationalization"><hr><h2>Internationalization</h2> <a name="Internationalization"><hr><h2>Internationalization</h2>
<center><i><b>Welcome to Babylon!</b></i></center><p> <center><i><b>Welcome to Babylon!</b></i></center><p>
@ -519,7 +604,7 @@ const tI18nPhrase Phrases[] = {
{ NULL } { NULL }
}; };
void cPluginDemo::Start(void) void cPluginHello::Start(void)
{ {
RegisterI18n(Phrases); RegisterI18n(Phrases);
} }
@ -557,20 +642,20 @@ core VDR code.
Plugins are loaded into VDR using the command line option <b><tt>-P</tt></b>, as in Plugins are loaded into VDR using the command line option <b><tt>-P</tt></b>, as in
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
vdr -Pdemo vdr -Phello
</pre></td></tr></table><p> </pre></td></tr></table><p>
If the plugin accepts command line options, they are given as part of the argument If the plugin accepts command line options, they are given as part of the argument
to the <b><tt>-P</tt></b> option, which then has to be enclosed in quotes: to the <b><tt>-P</tt></b> option, which then has to be enclosed in quotes:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
vdr -P"demo -a abc -b" vdr -P"hello -a abc -b"
</pre></td></tr></table><p> </pre></td></tr></table><p>
Any number of plugins can be loaded this way, each with its own <b><tt>-P</tt></b> option: Any number of plugins can be loaded this way, each with its own <b><tt>-P</tt></b> option:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
vdr -P"demo -a abc -b" -Pdvd -Pmp3 vdr -P"hello -a abc -b" -Pdvd -Pmp3
</pre></td></tr></table><p> </pre></td></tr></table><p>
If you are not starting VDR from the VDR source directory (and thus your plugins If you are not starting VDR from the VDR source directory (and thus your plugins
@ -578,7 +663,7 @@ cannot be found at their default location) you need to tell VDR the location of
the plugins through the <b><tt>-L</tt></b> option: the plugins through the <b><tt>-L</tt></b> option:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
vdr -L/usr/lib/vdr -Pdemo vdr -L/usr/lib/vdr -Phello
</pre></td></tr></table><p> </pre></td></tr></table><p>
There can be any number of <b><tt>-L</tt></b> options, and each of them will apply to the There can be any number of <b><tt>-L</tt></b> options, and each of them will apply to the
@ -603,17 +688,17 @@ provides the target <tt>package</tt>, which does this for you.
Simply change into your source directory and execute <tt>make package</tt>: Simply change into your source directory and execute <tt>make package</tt>:
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
cd VDR/PLUGINS/src/demo cd VDR/PLUGINS/src/hello
make package make package
</pre></td></tr></table><p> </pre></td></tr></table><p>
After this you should find a file named like After this you should find a file named like
<p><table><tr><td bgcolor=#F0F0F0><pre><br> <p><table><tr><td bgcolor=#F0F0F0><pre><br>
vdr-demo-0.0.1.tgz vdr-hello-0.0.1.tgz
</pre></td></tr></table><p> </pre></td></tr></table><p>
in your source directory, where <tt>demo</tt> will be replaced with your actual in your source directory, where <tt>hello</tt> will be replaced with your actual
plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number. plugin's name, and <tt>0.0.1</tt> will be your plugin's current version number.
</body> </body>

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: config.c 1.99 2002/05/05 12:00:00 kls Exp $ * $Id: config.c 1.100 2002/05/11 12:05:22 kls Exp $
*/ */
#include "config.h" #include "config.h"
@ -1073,14 +1073,19 @@ bool cSetup::Load(const char *FileName)
if (cConfig<cSetupLine>::Load(FileName, true)) { if (cConfig<cSetupLine>::Load(FileName, true)) {
bool result = true; bool result = true;
for (cSetupLine *l = First(); l; l = Next(l)) { for (cSetupLine *l = First(); l; l = Next(l)) {
bool error = false;
if (l->Plugin()) { if (l->Plugin()) {
cPlugin *p = cPluginManager::GetPlugin(l->Plugin()); cPlugin *p = cPluginManager::GetPlugin(l->Plugin());
if (p && !p->SetupParse(l->Name(), l->Value())) if (p && !p->SetupParse(l->Name(), l->Value()))
result = false; error = true;
} }
else { else {
if (!Parse(l->Name(), l->Value())) if (!Parse(l->Name(), l->Value()))
result = false; error = true;
}
if (error) {
esyslog(LOG_ERR, "ERROR: unknown config parameter: %s%s%s = %s", l->Plugin() ? l->Plugin() : "", l->Plugin() ? "." : "", l->Name(), l->Value());
result = false;
} }
} }
return result; return result;

15
i18n.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: i18n.c 1.87 2002/05/09 13:40:51 kls Exp $ * $Id: i18n.c 1.88 2002/05/11 11:43:38 kls Exp $
* *
* Translations provided by: * Translations provided by:
* *
@ -1270,6 +1270,19 @@ const tI18nPhrase Phrases[] = {
"Plugins", "Plugins",
"Plugins", "Plugins",
}, },
{ "Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
"Plugin",
},
{ "Restart", { "Restart",
"Neustart", "Neustart",
"Ponoven zagon", "Ponoven zagon",

192
menu.c
View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menu.c 1.190 2002/05/09 10:13:47 kls Exp $ * $Id: menu.c 1.191 2002/05/11 11:16:32 kls Exp $
*/ */
#include "menu.h" #include "menu.h"
@ -1525,19 +1525,41 @@ eOSState cMenuRecordings::ProcessKey(eKeys Key)
return state; return state;
} }
// --- cMenuSetupBase --------------------------------------------------------
class cMenuSetupBase : public cMenuSetupPage {
protected:
cSetup data;
virtual void Store(void);
public:
cMenuSetupBase(void);
};
cMenuSetupBase::cMenuSetupBase(void)
{
data = Setup;
}
void cMenuSetupBase::Store(void)
{
Setup = data;
Setup.Save();
}
// --- cMenuSetupOSD --------------------------------------------------------- // --- cMenuSetupOSD ---------------------------------------------------------
class cMenuSetupOSD : public cMenuSetupPage { class cMenuSetupOSD : public cMenuSetupBase {
private: private:
virtual void Set(void); virtual void Set(void);
public: public:
cMenuSetupOSD(void) { Set(); } cMenuSetupOSD(void) { Set(); }
virtual eOSState ProcessKey(eKeys Key);
}; };
void cMenuSetupOSD::Set(void) void cMenuSetupOSD::Set(void)
{ {
Clear(); Clear();
SetupTitle("OSD"); SetSection(tr("OSD"));
Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, I18nNumLanguages, I18nLanguages())); Add(new cMenuEditStraItem(tr("Setup.OSD$Language"), &data.OSDLanguage, I18nNumLanguages, I18nLanguages()));
Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH)); Add(new cMenuEditIntItem( tr("Setup.OSD$Width"), &data.OSDwidth, MINOSDWIDTH, MAXOSDWIDTH));
Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT)); Add(new cMenuEditIntItem( tr("Setup.OSD$Height"), &data.OSDheight, MINOSDHEIGHT, MAXOSDHEIGHT));
@ -1549,19 +1571,31 @@ void cMenuSetupOSD::Set(void)
Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs)); Add(new cMenuEditBoolItem(tr("Setup.OSD$Recording directories"), &data.RecordingDirs));
} }
eOSState cMenuSetupOSD::ProcessKey(eKeys Key)
{
int osdLanguage = data.OSDLanguage;
eOSState state = cMenuSetupBase::ProcessKey(Key);
if (data.OSDLanguage != osdLanguage) {
int OriginalOSDLanguage = Setup.OSDLanguage;
Setup.OSDLanguage = data.OSDLanguage;
Set();
Display();
Setup.OSDLanguage = OriginalOSDLanguage;
}
return state;
}
// --- cMenuSetupEPG --------------------------------------------------------- // --- cMenuSetupEPG ---------------------------------------------------------
class cMenuSetupEPG : public cMenuSetupPage { class cMenuSetupEPG : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupEPG(void) { Set(); } cMenuSetupEPG(void);
}; };
void cMenuSetupEPG::Set(void) cMenuSetupEPG::cMenuSetupEPG(void)
{ {
Clear(); SetSection(tr("EPG"));
SetupTitle("EPG");
Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout)); Add(new cMenuEditIntItem( tr("Setup.EPG$EPG scan timeout (h)"), &data.EPGScanTimeout));
Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL)); Add(new cMenuEditIntItem( tr("Setup.EPG$EPG bugfix level"), &data.EPGBugfixLevel, 0, MAXEPGBUGFIXLEVEL));
Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime)); Add(new cMenuEditBoolItem(tr("Setup.EPG$Set system time"), &data.SetSystemTime));
@ -1570,34 +1604,43 @@ void cMenuSetupEPG::Set(void)
// --- cMenuSetupDVB --------------------------------------------------------- // --- cMenuSetupDVB ---------------------------------------------------------
class cMenuSetupDVB : public cMenuSetupPage { class cMenuSetupDVB : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupDVB(void) { Set(); } cMenuSetupDVB(void);
virtual eOSState ProcessKey(eKeys Key);
}; };
void cMenuSetupDVB::Set(void) cMenuSetupDVB::cMenuSetupDVB(void)
{ {
Clear(); SetSection(tr("DVB"));
SetupTitle("DVB");
Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis)); Add(new cMenuEditIntItem( tr("Setup.DVB$Primary DVB interface"), &data.PrimaryDVB, 1, cDvbApi::NumDvbApis));
Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9")); Add(new cMenuEditBoolItem(tr("Setup.DVB$Video format"), &data.VideoFormat, "4:3", "16:9"));
} }
eOSState cMenuSetupDVB::ProcessKey(eKeys Key)
{
int oldPrimaryDVB = Setup.PrimaryDVB;
eOSState state = cMenuSetupBase::ProcessKey(Key);
if (state == osBack && Key == kOk) {
if (Setup.PrimaryDVB != oldPrimaryDVB) {
state = osSwitchDvb;
cDvbApi::PrimaryDvbApi->SetVideoFormat(Setup.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3);
}
}
return state;
}
// --- cMenuSetupLNB --------------------------------------------------------- // --- cMenuSetupLNB ---------------------------------------------------------
class cMenuSetupLNB : public cMenuSetupPage { class cMenuSetupLNB : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupLNB(void) { Set(); } cMenuSetupLNB(void);
}; };
void cMenuSetupLNB::Set(void) cMenuSetupLNB::cMenuSetupLNB(void)
{ {
Clear(); SetSection(tr("LNB"));
SetupTitle("LNB");
Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF)); Add(new cMenuEditIntItem( tr("Setup.LNB$SLOF (MHz)"), &data.LnbSLOF));
Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo)); Add(new cMenuEditIntItem( tr("Setup.LNB$Low LNB frequency (MHz)"), &data.LnbFrequLo));
Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi)); Add(new cMenuEditIntItem( tr("Setup.LNB$High LNB frequency (MHz)"), &data.LnbFrequHi));
@ -1606,17 +1649,15 @@ void cMenuSetupLNB::Set(void)
// --- cMenuSetupCICAM ------------------------------------------------------- // --- cMenuSetupCICAM -------------------------------------------------------
class cMenuSetupCICAM : public cMenuSetupPage { class cMenuSetupCICAM : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupCICAM(void) { Set(); } cMenuSetupCICAM(void);
virtual eOSState ProcessKey(eKeys Key);
}; };
void cMenuSetupCICAM::Set(void) cMenuSetupCICAM::cMenuSetupCICAM(void)
{ {
Clear(); SetSection(tr("CICAM"));
SetupTitle("CICAM");
for (int d = 0; d < cDvbApi::NumDvbApis; d++) { for (int d = 0; d < cDvbApi::NumDvbApis; d++) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
char buffer[32]; char buffer[32];
@ -1626,19 +1667,25 @@ void cMenuSetupCICAM::Set(void)
} }
} }
eOSState cMenuSetupCICAM::ProcessKey(eKeys Key)
{
eOSState state = cMenuSetupBase::ProcessKey(Key);
if (state == osBack && Key == kOk)
cDvbApi::SetCaCaps();
return state;
}
// --- cMenuSetupRecord ------------------------------------------------------ // --- cMenuSetupRecord ------------------------------------------------------
class cMenuSetupRecord : public cMenuSetupPage { class cMenuSetupRecord : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupRecord(void) { Set(); } cMenuSetupRecord(void);
}; };
void cMenuSetupRecord::Set(void) cMenuSetupRecord::cMenuSetupRecord(void)
{ {
Clear(); SetSection(tr("Recording"));
SetupTitle("Recording");
Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart)); Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at start (min)"), &data.MarginStart));
Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop)); Add(new cMenuEditIntItem( tr("Setup.Recording$Margin at stop (min)"), &data.MarginStop));
Add(new cMenuEditIntItem( tr("Setup.Recording$Primary limit"), &data.PrimaryLimit, 0, MAXPRIORITY)); Add(new cMenuEditIntItem( tr("Setup.Recording$Primary limit"), &data.PrimaryLimit, 0, MAXPRIORITY));
@ -1655,34 +1702,28 @@ void cMenuSetupRecord::Set(void)
// --- cMenuSetupReplay ------------------------------------------------------ // --- cMenuSetupReplay ------------------------------------------------------
class cMenuSetupReplay : public cMenuSetupPage { class cMenuSetupReplay : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupReplay(void) { Set(); } cMenuSetupReplay(void);
}; };
void cMenuSetupReplay::Set(void) cMenuSetupReplay::cMenuSetupReplay(void)
{ {
Clear(); SetSection(tr("Replay"));
SetupTitle("Replay");
Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode)); Add(new cMenuEditBoolItem(tr("Setup.Replay$Multi speed mode"), &data.MultiSpeedMode));
Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode)); Add(new cMenuEditBoolItem(tr("Setup.Replay$Show replay mode"), &data.ShowReplayMode));
} }
// --- cMenuSetupMisc -------------------------------------------------------- // --- cMenuSetupMisc --------------------------------------------------------
class cMenuSetupMisc : public cMenuSetupPage { class cMenuSetupMisc : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupMisc(void) { Set(); } cMenuSetupMisc(void);
}; };
void cMenuSetupMisc::Set(void) cMenuSetupMisc::cMenuSetupMisc(void)
{ {
Clear(); SetSection(tr("Miscellaneous"));
SetupTitle("Miscellaneous");
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. event timeout (min)"), &data.MinEventTimeout));
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$Min. user inactivity (min)"), &data.MinUserInactivity));
Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout)); Add(new cMenuEditIntItem( tr("Setup.Miscellaneous$SVDRP timeout (s)"), &data.SVDRPTimeout));
@ -1706,18 +1747,15 @@ cMenuSetupPluginItem::cMenuSetupPluginItem(const char *Name, int Index)
// --- cMenuSetupPlugins ----------------------------------------------------- // --- cMenuSetupPlugins -----------------------------------------------------
class cMenuSetupPlugins : public cMenuSetupPage { class cMenuSetupPlugins : public cMenuSetupBase {
private:
virtual void Set(void);
public: public:
cMenuSetupPlugins(void) { Set(); } cMenuSetupPlugins(void);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
void cMenuSetupPlugins::Set(void) cMenuSetupPlugins::cMenuSetupPlugins(void)
{ {
Clear(); SetSection(tr("Plugins"));
SetupTitle("Plugins");
SetHasHotkeys(); SetHasHotkeys();
for (int i = 0; ; i++) { for (int i = 0; ; i++) {
cPlugin *p = cPluginManager::GetPlugin(i); cPlugin *p = cPluginManager::GetPlugin(i);
@ -1734,25 +1772,25 @@ void cMenuSetupPlugins::Set(void)
eOSState cMenuSetupPlugins::ProcessKey(eKeys Key) eOSState cMenuSetupPlugins::ProcessKey(eKeys Key)
{ {
eOSState state = cOsdMenu::ProcessKey(Key); // not cMenuSetupPage::ProcessKey()! eOSState state = HasSubMenu() ? cMenuSetupBase::ProcessKey(Key) : cOsdMenu::ProcessKey(Key);
if (state == osUnknown) { if (Key == kOk) {
switch (Key) { if (state == osUnknown) {
case kOk: { cMenuSetupPluginItem *item = (cMenuSetupPluginItem *)Get(Current());
cMenuSetupPluginItem *item = (cMenuSetupPluginItem *)Get(Current()); if (item) {
if (item) { cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex());
cPlugin *p = cPluginManager::GetPlugin(item->PluginIndex()); if (p) {
if (p) { cMenuSetupPage *menu = p->SetupMenu();
cOsdMenu *menu = p->SetupMenu(); if (menu) {
if (menu) menu->SetPlugin(p);
return AddSubMenu(menu); return AddSubMenu(menu);
Interface->Info(tr("This plugin has no setup parameters!")); }
} Interface->Info(tr("This plugin has no setup parameters!"));
} }
} }
break; }
default: break; else if (state == osContinue)
} Store();
} }
return state; return state;
} }

View File

@ -4,12 +4,13 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menuitems.c 1.1 2002/05/09 10:10:12 kls Exp $ * $Id: menuitems.c 1.2 2002/05/11 10:49:45 kls Exp $
*/ */
#include "menuitems.h" #include "menuitems.h"
#include <ctype.h> #include <ctype.h>
#include "i18n.h" #include "i18n.h"
#include "plugin.h"
// --- cMenuEditItem --------------------------------------------------------- // --- cMenuEditItem ---------------------------------------------------------
@ -437,15 +438,13 @@ eOSState cMenuTextItem::ProcessKey(eKeys Key)
cMenuSetupPage::cMenuSetupPage(void) cMenuSetupPage::cMenuSetupPage(void)
:cOsdMenu("", 33) :cOsdMenu("", 33)
{ {
data = Setup; plugin = NULL;
osdLanguage = Setup.OSDLanguage;
} }
void cMenuSetupPage::SetupTitle(const char *s) void cMenuSetupPage::SetSection(const char *Section)
{ {
char buf[40]; // can't call tr() for more than one string at a time! char buf[40];
char *q = buf + snprintf(buf, sizeof(buf), "%s - ", tr("Setup")); snprintf(buf, sizeof(buf), "%s - %s", tr("Setup"), Section);
snprintf(q, sizeof(buf) - strlen(buf), "%s", tr(s));
SetTitle(buf); SetTitle(buf);
} }
@ -455,22 +454,31 @@ eOSState cMenuSetupPage::ProcessKey(eKeys Key)
if (state == osUnknown) { if (state == osUnknown) {
switch (Key) { switch (Key) {
case kOk: state = (Setup.PrimaryDVB != data.PrimaryDVB) ? osSwitchDvb : osBack; case kOk: Store();
cDvbApi::PrimaryDvbApi->SetVideoFormat(data.VideoFormat ? VIDEO_FORMAT_16_9 : VIDEO_FORMAT_4_3); state = osBack;
Setup = data;
Setup.Save();
cDvbApi::SetCaCaps();
break; break;
default: break; default: break;
} }
} }
if (data.OSDLanguage != osdLanguage) {
int OriginalOSDLanguage = Setup.OSDLanguage;
Setup.OSDLanguage = data.OSDLanguage;
Set();
Display();
osdLanguage = data.OSDLanguage;
Setup.OSDLanguage = OriginalOSDLanguage;
}
return state; return state;
} }
void cMenuSetupPage::SetPlugin(cPlugin *Plugin)
{
plugin = Plugin;
char buf[40];
snprintf(buf, sizeof(buf), "%s '%s'", tr("Plugin"), plugin->Name());
SetSection(buf);
}
void cMenuSetupPage::SetupStore(const char *Name, const char *Value = NULL)
{
if (plugin)
plugin->SetupStore(Name, Value);
}
void cMenuSetupPage::SetupStore(const char *Name, int Value)
{
if (plugin)
plugin->SetupStore(Name, Value);
}

View File

@ -4,7 +4,7 @@
* See the main source file 'vdr.c' for copyright information and * See the main source file 'vdr.c' for copyright information and
* how to reach the author. * how to reach the author.
* *
* $Id: menuitems.h 1.1 2002/05/09 09:41:06 kls Exp $ * $Id: menuitems.h 1.2 2002/05/11 10:48:28 kls Exp $
*/ */
#ifndef __MENUITEMS_H #ifndef __MENUITEMS_H
@ -96,15 +96,20 @@ public:
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
}; };
class cPlugin;
class cMenuSetupPage : public cOsdMenu { class cMenuSetupPage : public cOsdMenu {
private:
cPlugin *plugin;
protected: protected:
cSetup data; void SetSection(const char *Section);
int osdLanguage; virtual void Store(void) = 0;
void SetupTitle(const char *s); void SetupStore(const char *Name, const char *Value = NULL);
virtual void Set(void) = 0; void SetupStore(const char *Name, int Value);
public: public:
cMenuSetupPage(void); cMenuSetupPage(void);
virtual eOSState ProcessKey(eKeys Key); virtual eOSState ProcessKey(eKeys Key);
void SetPlugin(cPlugin *Plugin);
}; };
#endif //__MENUITEMS_H #endif //__MENUITEMS_H

10
vdr.c
View File

@ -22,7 +22,7 @@
* *
* The project's page is at http://www.cadsoft.de/people/kls/vdr * The project's page is at http://www.cadsoft.de/people/kls/vdr
* *
* $Id: vdr.c 1.104 2002/05/05 12:00:00 kls Exp $ * $Id: vdr.c 1.105 2002/05/11 11:46:40 kls Exp $
*/ */
#include <getopt.h> #include <getopt.h>
@ -578,14 +578,14 @@ int main(int argc, char *argv[])
} }
if (Interrupted) if (Interrupted)
isyslog(LOG_INFO, "caught signal %d", Interrupted); isyslog(LOG_INFO, "caught signal %d", Interrupted);
Setup.CurrentChannel = cDvbApi::CurrentChannel();
Setup.CurrentVolume = cDvbApi::CurrentVolume();
Setup.Save();
PluginManager.Shutdown(true);
cVideoCutter::Stop(); cVideoCutter::Stop();
delete Menu; delete Menu;
delete ReplayControl; delete ReplayControl;
delete Interface; delete Interface;
PluginManager.Shutdown(true);
Setup.CurrentChannel = cDvbApi::CurrentChannel();
Setup.CurrentVolume = cDvbApi::CurrentVolume();
Setup.Save();
cDvbApi::Cleanup(); cDvbApi::Cleanup();
if (WatchdogTimeout > 0) if (WatchdogTimeout > 0)
dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime); dsyslog(LOG_INFO, "max. latency time %d seconds", MaxLatencyTime);