Index: libs/libmythui/myththemedmenu.h
===================================================================
--- libs/libmythui/myththemedmenu.h	(revision 24007)
+++ libs/libmythui/myththemedmenu.h	(working copy)
@@ -61,6 +61,8 @@
     void CopyFrom(MythUIType*);
 };
 
+class QDomDocument;
+
 /// \brief Themed menu class, used for main menus in %MythTV frontend
 class MPUBLIC MythThemedMenu : public MythThemedMenuState
 {
@@ -94,9 +96,13 @@
     void buttonAction(MythUIButtonListItem* item, bool skipPass = false);
 
   private:
-    void Init(const QString &menufile);
+    MythThemedMenu(const QString command, MythScreenStack *parent,
+                    MythThemedMenuState *state);
 
+    void Init(MythScreenStack *parent, MythThemedMenuState *state);
+
     bool parseMenu(const QString &menuname);
+    bool parseMenu(const QDomDocument &doc, const QString &menuname);
     void parseThemeButton(QDomElement &element);
 
     void addButton(const QString &type, const QString &text,
Index: libs/libmythui/myththemedmenu.cpp
===================================================================
--- libs/libmythui/myththemedmenu.cpp	(revision 24007)
+++ libs/libmythui/myththemedmenu.cpp	(working copy)
@@ -7,6 +7,7 @@
 #include <QKeyEvent>
 #include <QDomDocument>
 #include <QFile>
+#include <QProcess>
 
 // Mythui headers
 #include "mythmainwindow.h"
@@ -93,6 +94,75 @@
       m_state(state), m_allocedstate(false), m_foundtheme(false),
       m_exitModifier(0), m_ignorekeys(false), m_wantpop(false)
 {
+    Init(parent, state);
+
+    if (!parseMenu(menufile))
+        m_foundtheme = false;
+}
+
+/** \brief Creates a dynamic themed menu.
+ *
+ *  \param command      external command to execute
+ *  \param parent       the screen stack that owns this UI type
+ *  \param state        theme state associated with this menu
+ */
+MythThemedMenu::MythThemedMenu(const QString command, MythScreenStack *parent,
+                               MythThemedMenuState *state)
+              : MythThemedMenuState(parent, command)
+{
+    Init(parent, state);
+
+    QProcess process;
+    process.start(command);
+    if (!process.waitForFinished())
+    {
+        process.kill();
+        VERBOSE(VB_IMPORTANT,
+                QString("Command \"%1\" returned error\n").arg(command));
+        ShowOkPopup(QObject::tr("Couldn't execute %1")
+                    .arg(command));
+
+        m_foundtheme = false;
+        return;
+    }
+    else
+    {
+        QString errorMsg;
+        int errorLine = 0;
+        int errorColumn = 0;
+
+        QDomDocument doc;
+        if (!doc.setContent(process.readAllStandardOutput(), false,
+            &errorMsg, &errorLine, &errorColumn))
+        {
+            VERBOSE(VB_IMPORTANT,
+                    QString("Error parsing output of: %1\nat line: %2  column: %3 msg: %4").
+                    arg(command).arg(errorLine).arg(errorColumn).arg(errorMsg));
+
+            ShowOkPopup(QObject::tr("Command %1 returned incomplete menu.")
+                    .arg(command));
+
+            m_foundtheme = false;
+            return;
+        }
+
+        if (!parseMenu(doc, command))
+            m_foundtheme = false;
+    }
+}
+
+/** \brief Initializes the menu state.
+ *
+ *  \param parent       the screen stack that owns this UI type
+ *  \param state        theme state associated with this menu
+*/
+void MythThemedMenu::Init(MythScreenStack *parent, MythThemedMenuState *state)
+{
+    m_state = state;
+    m_allocedstate = m_foundtheme = m_ignorekeys = m_wantpop = false;
+    m_exitModifier = -1;
+    m_menumode = "";
+    m_buttonList = NULL;
     m_menuPopup = NULL;
 
     if (!m_state)
@@ -101,18 +171,6 @@
         m_allocedstate = true;
     }
 
-    Init(menufile);
-}
-
-/** \brief Loads the main UI theme, and a menu theme.
- *
- *  See also foundtheme(void), it will return true when called after
- *  this method if this method was successful.
- *
- *  \param menufile name of menu item xml file
- */
-void MythThemedMenu::Init(const QString &menufile)
-{
     ReloadExitKey();
 
     if (!m_state->m_loaded)
@@ -132,9 +190,6 @@
             SLOT(setButtonActive(MythUIButtonListItem*)));
     connect(m_buttonList, SIGNAL(itemClicked(MythUIButtonListItem*)),
             SLOT(buttonAction(MythUIButtonListItem*)));
-
-    if (!parseMenu(menufile))
-        m_foundtheme = false;
 }
 
 MythThemedMenu::~MythThemedMenu(void)
@@ -495,8 +550,7 @@
                 if (text.isEmpty() &&
                     info.attribute("lang","").isEmpty())
                 {
-                    text = qApp->translate("ThemeUI",
-                                            qPrintable(getFirstText(info)));
+                    text = getFirstText(info);
                 }
                 else if (info.attribute("lang","").toLower() ==
                          GetMythUI()->GetLanguageAndVariant())
@@ -514,8 +568,7 @@
                 if (alttext.isEmpty() &&
                     info.attribute("lang","").isEmpty())
                 {
-                    alttext = qApp->translate("ThemeUI",
-                                            qPrintable(getFirstText(info)));
+                    alttext = getFirstText(info);
                 }
                 else if (info.attribute("lang","").toLower() ==
                          GetMythUI()->GetLanguageAndVariant())
@@ -653,6 +706,14 @@
 
     VERBOSE(VB_GENERAL, QString("Loading menu theme from %1").arg(filename));
 
+    return parseMenu(doc, menuname);
+}
+
+/** \brief Parse the themebuttons to be added based on the contents
+ *         of the provided XML document.
+ */
+bool MythThemedMenu::parseMenu(const QDomDocument &doc, const QString &menuname)
+{
     QDomElement docElem = doc.documentElement();
 
     m_menumode = docElem.attribute("name", "MAIN");
@@ -834,6 +895,19 @@
         else
             delete newmenu;
     }
+    else if (action.left(9) == "MENUEXEC ")
+    {
+        QString command = action.mid(9);
+
+        MythScreenStack *stack = GetScreenStack();
+
+        MythThemedMenu *newmenu = new MythThemedMenu(command, stack, m_state);
+
+        if (newmenu->foundTheme())
+            stack->AddScreen(newmenu);
+        else
+            delete newmenu;
+    }
     else if (action.left(6) == "UPMENU")
     {
         m_wantpop = true;
