Index: mythtv/libs/libmyth/xmlparse.h
===================================================================
--- mythtv/libs/libmyth/xmlparse.h	(revision 14385)
+++ mythtv/libs/libmyth/xmlparse.h	(working copy)
@@ -55,7 +55,7 @@
     void parseKey(LayerSet *, QDomElement &);
  
   private:
-    bool doLoadTheme(QDomElement &, QString, QString);
+    bool doLoadTheme(QDomElement &, QString, QString, QStringList);
     QMap<QString, fontProp> fontMap;
     QMap<QString, LayerSet*> layerMap;
     vector<LayerSet *> *allTypes;
@@ -64,7 +64,9 @@
     double hmult;
 
     int usetrans;
-    
+
+    enum {INCLUDE_RECURSION_LIMIT = 10};
+
     QString fontSizeType;
 };
 
Index: mythtv/libs/libmyth/xmlparse.cpp
===================================================================
--- mythtv/libs/libmyth/xmlparse.cpp	(revision 14385)
+++ mythtv/libs/libmyth/xmlparse.cpp	(working copy)
@@ -34,35 +34,46 @@
     fontSizeType = gContext->GetSetting("ThemeFontSizeType", "default");
 
     QValueList<QString> searchpath = gContext->GetThemeSearchPath();
-    for (QValueList<QString>::const_iterator ii = searchpath.begin();
-        ii != searchpath.end(); ii++)
+
+    QString themefile = specialfile + "ui.xml";
+
+    if (doLoadTheme(ele, winName, themefile, searchpath))
     {
-        QString themefile = *ii + specialfile + "ui.xml";
-        if (doLoadTheme(ele, winName, themefile))
-        {
-            VERBOSE(VB_GENERAL, "XMLParse::LoadTheme using " << themefile);
-            return true;
-        }
+        VERBOSE(VB_GENERAL, "XMLParse::LoadTheme using " << themefile);
+        return true;
     }
-    
+
     return false;
 }
 
-bool XMLParse::doLoadTheme(QDomElement &ele, QString winName, QString themeFile)
+bool XMLParse::doLoadTheme(QDomElement &ele, QString winName,
+        QString themeFile, QStringList searchpath)
 {
-    QDomDocument doc;
-    QFile f(themeFile);
+    QFile f;
+    bool fileSuccess = false;
+    for (QValueList<QString>::const_iterator ii = searchpath.begin();
+            ii != searchpath.end(); ii++)
+    {
+        f.setName( *ii + themeFile );
+        if (f.open(IO_ReadOnly))
+        {
+            fileSuccess = true;
+            break;
+        }
+    }
 
-    if (!f.open(IO_ReadOnly))
-    {    
-        //cerr << "XMLParse::LoadTheme(): Can't open: " << themeFile << endl;
+    if (!fileSuccess)
+    {
+        cerr << "XMLParse::LoadTheme(): Can't open: " << themeFile << endl;
         return false;
     }
-     
+
+    QDomDocument doc;
     QString errorMsg;
     int errorLine = 0;
     int errorColumn = 0;
 
+    // Create xml document, report erros
     if (!doc.setContent(&f, false, &errorMsg, &errorLine, &errorColumn))
     {
         cerr << "Error parsing: " << themeFile << endl;
@@ -71,10 +82,85 @@
         f.close();
         return false;
     }
-
     f.close();
+    QDomElement docElem = doc.documentElement();
 
-    QDomElement docElem = doc.documentElement();
+    QDomDocument incDoc;
+    uint includeRecursionCount = 0;
+
+    // Find include elements
+    QDomNodeList includeFileList = docElem.elementsByTagName("include_file");
+    while ( includeFileList.count() )
+    {
+        // Node to be replaced in original document
+        QDomNode replacementNode = includeFileList.item(0);
+
+        // Get include file name
+        QString includeFile = replacementNode.toElement().attribute("src","");
+        if (includeFile.isEmpty())
+        {
+            cerr << "Expecting <include_file src=\"filename.xml\"/>" << endl;
+            return false;
+        }
+
+        QFile g;
+        fileSuccess = false;
+        for (QValueList<QString>::const_iterator ii = searchpath.begin();
+                ii != searchpath.end(); ii++)
+        {
+            g.setName( *ii + includeFile );
+            if (g.open(IO_ReadOnly))
+            {
+                fileSuccess = true;
+                break;
+            }
+        }
+
+        if (!fileSuccess)
+        {
+            cerr << "XMLParse::LoadTheme(): Can't open include_file: "
+                << includeFile << endl;
+            return false;
+        }
+
+        // Import doc reporting on errors
+        if (!incDoc.setContent(&g, false, &errorMsg, &errorLine, &errorColumn))
+        {
+            cerr << "Error parsing: " << includeFile << endl;
+            cerr << "at line: " << errorLine
+                 << "  column: " << errorColumn << endl;
+            cerr << errorMsg << endl;
+            cerr << "Includes MUST be valid XML documents"
+                    " with a single root element!" << endl;
+            g.close();
+            return false;
+        }
+        g.close();
+
+        // Insert all children from the include file root
+        QDomNodeList includeNodeList = incDoc.documentElement().childNodes();
+        while( includeNodeList.count() )
+            replacementNode.parentNode()
+                .insertBefore( includeNodeList.item(0), replacementNode );
+
+        if ( docElem.isNull() )
+        {
+            cerr << "*** Error detected whilst including \""
+                 << includeFile << "\"!" << endl;
+            return false;
+        }
+
+        // Error out if include recursion limit met
+        if ( ++includeRecursionCount >= INCLUDE_RECURSION_LIMIT )
+        {
+            cerr << "Error recursion limit reached: " << INCLUDE_RECURSION_LIMIT << endl;
+            return false;
+        }
+
+        // Delete <include_file>s
+        replacementNode.parentNode().removeChild( replacementNode );
+    }
+
     QDomNode n = docElem.firstChild();
     while (!n.isNull())
     {
