Building Plugins:HelloMyth
From MythTV
Contents |
Creating Your First Plugin: Hello Myth
This is a really simple skeleton plugin that doesn't do anything. It'll show you what is absolutely necessary to create a plugin, then you can expand on that by dissecting others.
As a disclaimer, I am also very new to plugin development and so please correct me where I might be wrong.
To start, download the mythplugin directory from SVN and create the following directory tree within its:
svn co http://svn.mythtv.org/svn/trunk/mythplugins mkdir -p mythplugins/mythhello/mythhello
You will also need to install some development tools if you don't already have them (qmake-qt4 for newer mythtv, or qmake for older versions). For example:
sudo apt-get install qt4-qmake libqt4-dev
mythhello.pro Files
The *.pro files are used by qmake to create the Makefiles.
1) Create a file called mythhello.pro in the first mythhello directory:
TEMPLATE = subdirs # Directories SUBDIRS = mythhello
"mythhello" refers to the second mythhello directory.
2) Create another file called mythhello.pro in the second mythhello (mythplugins/mythhello/mythhello/mythhello.pro) directory
include ( ../../mythconfig.mak )
include ( ../../settings.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
}
The following items are specific to your plugin: 'uifiles.files', 'installfiles.files', 'HEADERS', 'SOURCES'. Be sure that $${LIBDIR} and $${PREFIX} are set in mythplugins/mythconfig.mak to be the mythtv install prefix and library directory. Mine are set to:
PREFIX=/usr/ LIBDIR=/usr/lib/
(Note: I didn't find a mythplugins/mythconfig.mak but adding the above two lines to the top of my mythhello.mak worked to set the paths correctly - using a 0.21 system.)
(Note2: You can execute the configure script in mythplugins to generate the mythconfig.mak file. Depending on where your mythtv is located it may be necessary to add the argument --prefix=/usr)
CPP Files
Now we create the cpp/h files which should be put in mythplugins/mythhello/mythhello/.
Here's the main file that takes care of initializing, running and destructing the pluigin:
// C++ headers
#include <unistd.h>
// QT headers
#include <QApplication>
// MythTV headers
#include <mythcontext.h>
#include <mythplugin.h>
#include <mythpluginapi.h>
#include <mythversion.h>
#include <mythmainwindow.h>
// 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)
{
}
#ifndef MYTHHELLO_H
#define MYTHHELLO_H
// MythTV headers
#include <mythscreentype.h>
#include <mythuibutton.h>
/** \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 */
// POSIX headers
#include <unistd.h>
// MythTV headers
#include <mythuibutton.h>
#include <mythuitext.h>
#include <mythmainwindow.h>
#include <mythcontext.h>
#include <mythdirs.h>
// 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"));
}
The UI File
What would a plugin be without a UI? Now create hello-ui.xml and put it in mythplugins/mythhello/mythhello/.
<?xml version="1.0" encoding="utf-8"?>
<mythuitheme>
<window name="hello">
<textarea name="title">
<area>0,10,800,100</area>
<font>large</font>
<align>allcenter</align>
<multiline>yes</multiline>
<value>Hello World</value>
</textarea>
<textarea name="outtext">
<area>0,300,800,100</area>
<font>large</font>
<align>allcenter</align>
<multiline>yes</multiline>
</textarea>
<button name="cancel" from="basebutton">
<position>500,400</position>
<value>Cancel</value>
</button>
<button name="ok" from="basebutton">
<position>200,400</position>
<value>OK</value>
</button>
</window>
</mythuitheme>
Building
Go to the top mythhello directory (mythplugins/mythhello) and run these commands:
su qmake-qt4 make make install
Make sure everything compiled OK and the files where copied to your mythtv installation directories.
Adding MythHello to your Menus
As a final step you have to add your plugin to the main MythTv menu -- in my case /usr/share/mythtv/mainmenu.xml. Add the following anywhere in the XML file between the <mythmenu> root tag:
<button> <type>HELLO_MYTH</type> <text>Hello Myth</text> <action>PLUGIN mythhello</action> </button>
Finishing Up
Now restart MythFrontend and you should see a 'Hello Myth' button on the main menu.
Good Luck
- Mozmonkey
