I'm a big fan of MythTV, having used it for years as a very comprehensive media centre.
MythTV also provides an excellent extension framework, which is a good excuse as any to have a bash at some development under Linux for a change.
This post starts at the beginning: getting a hello world plugin compiled and running. This is based heavily on the HelloMyth page on the MythTV Wiki, with tweaks needed for a vanilla MythTV 0.23 installation under Ubuntu 10.10.
Prerequisites
Assuming that you have a working MythTV installation, you will also need the following packages:
sudo apt-get install libmyth-dev qt4-qmake build-essential ccache libqt4-dev libfreetype6-dev libmp3lame-dev libasound2-dev libjack-dev libraw1394-dev libiec61883-dev libavc1394-dev libxv-dev libxvmc-dev
Once those are installed, grab a copy of the standard MythTV plugins from the myth git repository; note that you'll want to work with the branch of MythTV you have installed (unless you're working with the trunk version).
git clone -b fixes/0.23 git://github.com/MythTV/mythtv.git
Generate a config file by running the configure script in the mythplugins directory (You may or may not need the prefix argument, this is based on an Ubuntu 10.10 install):
./configure --prefix=/usr
Code
In the mythplugins folder, create a mythhello folder and add the following file:
mythhello/mythhello.pro
TEMPLATE = subdirs
# Directories
SUBDIRS = mythhello
Now inside the mythhello folder, create another mythhello folder, and add the following files:
mythhello/mythhello/mythhello.pro
include ( ../../mythconfig.mak )
include ( ../../settings.pro )
include ( ../../programs-libs.pro )
QT += network sql xml
TEMPLATE = lib
CONFIG += plugin thread
TARGET = mythhello
target.path = $${LIBDIR}/mythtv/plugins
INSTALLS += target
uifiles.path = $${PREFIX}/share/mythtv/themes/default
uifiles.files = hello-ui.xml
installfiles.path = $${PREFIX}/share/mythtv
installfiles.files = hello-ui.xml
INSTALLS += uifiles
# Input
HEADERS += mythhello.h
SOURCES += main.cpp mythhello.cpp
macx {
QMAKE_LFLAGS += -flat_namespace -undefined suppress
}
mythhello/mythhello/main.cpp (Entry point for the plugin)
// C++ headers
#include
// QT headers
#include
// MythTV headers
#include
#include
#include
#include
#include
// MythHello headers
#include "mythhello.h"
using namespace std;
void runHello(void);
int RunHello(void);
void setupKeys(void)
{
REG_JUMP("MythHello", QT_TRANSLATE_NOOP("MythHello",
"Sample plugin"), "", runHello);
}
int mythplugin_init(const char *libversion)
{
if (!gContext->TestPopupVersion("mythhello",
libversion,
MYTH_BINARY_VERSION))
return -1;
setupKeys();
return 0;
}
void runHello(void)
{
RunHello();
}
int RunHello(void)
{
MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack();
MythHello *mythhello = new MythHello(mainStack, "hello");
if (mythhello->Create())
{
mainStack->AddScreen(mythhello);
return 0;
}
else
{
delete mythhello;
return -1;
}
}
int mythplugin_run(void)
{
return RunHello();
}
int mythplugin_config(void)
{
}
mythhello/mythhello/mythhello.h (Plugin header)
#ifndef MYTHHELLO_H
#define MYTHHELLO_H
// MythTV headers
#include
#include
/** \class MythHello
* \brief Example plugin. Shows how to use Text areas and buttons
*/
class MythHello : public MythScreenType
{
Q_OBJECT
public:
MythHello(MythScreenStack *parent, QString name);
bool Create(void);
bool keyPressEvent(QKeyEvent *);
private:
MythUIText *m_titleText;
MythUIText *m_outText;
MythUIButton *m_cancelButton;
MythUIButton *m_okButton;
private slots:
void ok_clicked(void);
void cancel_clicked(void);
};
#endif /* MYTHHELLO_H */
mythhello/mythhello/mythhello.cpp (Main plugin body)
// POSIX headers
#include
// MythTV headers
#include
#include
#include
#include
#include
// MythHello headers
#include "mythhello.h"
#define LOC QString("MythHello: ")
#define LOC_WARN QString("MythHello, Warning: ")
#define LOC_ERR QString("MythHello, Error: ")
/** \brief Creates a new MythHello Screen
* \param parent Pointer to the screen stack
* \param name The name of the window
*/
MythHello::MythHello(MythScreenStack *parent, QString name) :
MythScreenType(parent, name),
m_cancelButton(NULL)
{
//example of how to find the configuration dir currently used.
QString confdir = GetConfDir();
VERBOSE(VB_IMPORTANT, LOC + "Conf dir:" + confdir);
}
bool MythHello::Create(void)
{
bool foundtheme = false;
// Load the theme for this screen
foundtheme = LoadWindowFromXML("hello-ui.xml", "hello", this);
if (!foundtheme)
return false;
bool err = false;
UIUtilE::Assign(this, m_titleText, "title", &err);
UIUtilE::Assign(this, m_outText, "outtext", &err);
UIUtilE::Assign(this, m_cancelButton, "cancel", &err);
UIUtilE::Assign(this, m_okButton, "ok", &err);
if (err)
{
VERBOSE(VB_IMPORTANT, "Cannot load screen 'hello'");
return false;
}
BuildFocusList();
SetFocusWidget(m_cancelButton);
connect(m_okButton, SIGNAL(Clicked()), this, SLOT(ok_clicked()));
connect(m_cancelButton, SIGNAL(Clicked()), this, SLOT(cancel_clicked()));
return true;
}
bool MythHello::keyPressEvent(QKeyEvent *event)
{
if (GetFocusWidget() && GetFocusWidget()->keyPressEvent(event))
return true;
bool handled = false;
QStringList actions;
handled = GetMythMainWindow()->TranslateKeyPress("Hello", event, actions);
for (int i = 0; i < actions.size() && !handled; i++)
{
QString action = actions[i];
handled = true;
if (action == "ESCAPE")
Close();
else
handled = false;
}
if (!handled && MythScreenType::keyPressEvent(event))
handled = true;
return handled;
}
void MythHello::ok_clicked(void)
{
m_outText->SetText(QString("OK clicked"));
}
void MythHello::cancel_clicked(void)
{
m_outText->SetText(QString("Cancel clicked"));
}
mythhello/mythhello/hello-ui.xml (Plugin UI definition)
large
0,300,800,100
large
Building
Change to mythplugins/mythhello and run the following:
qmake-qt4
make
sudo make install
Everything should be compiled and the plugin copied to /usr/lib/mythtv/plugins/.
To get the plugin to show up in the main menu edit /usr/share/mythtv/themes/defaultmenu/mainmenu.xml and add a new button entry:
On starting mythfrontend at this point, the plugin should show up on the main menu.
Summary
At this point we have a working MythTV plugin which will serve as a good starting point for building further functionality.