[Scummvm-git-logs] scummvm master -> 1c48e73347e97e0b007db839ac28212b15754ce4

sev- noreply at scummvm.org
Wed Mar 18 15:51:19 UTC 2026


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
1c48e73347 GUI: Parse unpacked themes


Commit: 1c48e73347e97e0b007db839ac28212b15754ce4
    https://github.com/scummvm/scummvm/commit/1c48e73347e97e0b007db839ac28212b15754ce4
Author: Mohamed Shaaban (117195948+sh3boly at users.noreply.github.com)
Date: 2026-03-18T16:51:15+01:00

Commit Message:
GUI: Parse unpacked themes

Changed paths:
    gui/ThemeEngine.cpp
    gui/ThemeEngine.h


diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp
index ac983be43bc..840c3c80160 100644
--- a/gui/ThemeEngine.cpp
+++ b/gui/ThemeEngine.cpp
@@ -340,7 +340,8 @@ bool ThemeEngine::init() {
 	if (!_themeArchive && !_themeFile.empty()) {
 		Common::FSNode node(_themeFile);
 		if (node.isDirectory()) {
-			_themeArchive = new Common::FSDirectory(node);
+			debug("Loading unpacked theme from %s", node.getPath().toString().c_str());
+			_themeArchive = createUnpackedThemeArchive(node);
 		} else if (_themeFile.baseName().matchString("*.zip", true)) {
 			// TODO: Also use "node" directly?
 			// Look for the zip file via SearchMan
@@ -880,6 +881,9 @@ bool ThemeEngine::loadThemeXML(const Common::String &themeId) {
 		return false;
 	}
 
+	if (!themeId.contains(".zip") && !themeId.contains(".ZIP"))
+		_themeName += " (unpacked)";
+
 	Common::ArchiveMemberList members;
 	if (0 == _themeArchive->listMatchingMembers(members, "*.stx")) {
 		warning("Found no STX files for theme '%s'.", themeId.c_str());
@@ -1924,6 +1928,14 @@ bool ThemeEngine::themeConfigUsable(const Common::ArchiveMember &member, Common:
 		}
 
 		delete zipArchive;
+	} else {
+		Common::FSNode dirNode(Common::Path(member.getName()));
+		if (dirNode.isDirectory()) {
+			Common::FSNode themeRcNode = dirNode.getChild("THEMERC");
+			if (themeRcNode.exists() && !themeRcNode.isDirectory()) {
+				stream.open(themeRcNode);
+			}
+		}
 	}
 
 	if (stream.isOpen()) {
@@ -1992,6 +2004,8 @@ void ThemeEngine::listUsableThemes(Common::List<ThemeDescriptor> &list) {
 
 	if (ConfMan.hasKey("themepath"))
 		listUsableThemes(Common::FSNode(ConfMan.getPath("themepath")), list);
+	else
+		listUsableThemes(Common::FSNode(Common::Path("gui/themes")), list);
 
 	listUsableThemes(SearchMan, list);
 
@@ -2038,6 +2052,50 @@ void ThemeEngine::listUsableThemes(Common::Archive &archive, Common::List<ThemeD
 	fileList.clear();
 }
 
+Common::Archive *ThemeEngine::createUnpackedThemeArchive(const Common::FSNode &themeDir) {
+	// Check if the directory has the THEMERC file
+	Common::FSNode themercNode = themeDir.getChild("THEMERC");
+	if (!themercNode.exists() || themercNode.isDirectory())
+		return 0;
+
+	Common::File themercFile;
+	if (!themercFile.open(themercNode))
+		return 0;
+
+	Common::SearchSet *archive = new Common::SearchSet();
+	archive->addDirectory(themeDir.getName(), themeDir, 0);
+
+	Common::String line;
+	int prio = 1;
+
+	// Parse the THEMERC file and extract the other directories
+	while (!themercFile.eos() && !themercFile.err()) {
+		line = themercFile.readLine();
+		line.trim();
+
+		if (line.hasPrefix("%using ")) {
+			Common::Path themePath = themeDir.getPath();
+			Common::String rawThemePath = line.substr(7);
+			rawThemePath.trim();
+
+			themePath = themePath.append(rawThemePath);
+
+			Common::Path normalizedThemePath = Common::Path(themePath).normalize();
+
+			Common::FSNode dir(normalizedThemePath);
+
+			if (dir.exists() && dir.isDirectory()) {
+				archive->addDirectory(dir.getName(), dir, prio++);
+			} else {
+				debug("ThemeEngine: Parsed path: %s from THEMERC doesn't exist", dir.getPath().toString().c_str());
+			}
+
+		}
+	}
+
+	return archive;
+}
+
 void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth) {
 	if (!node.exists() || !node.isReadable() || !node.isDirectory())
 		return;
@@ -2058,22 +2116,37 @@ void ThemeEngine::listUsableThemes(const Common::FSNode &node, Common::List<Them
 
 	Common::FSList fileList;
 	// Check all files. We need this to find all themes inside ZIP archives.
-	if (!node.getChildren(fileList, Common::FSNode::kListFilesOnly))
+	if (!node.getChildren(fileList, Common::FSNode::kListAll))
 		return;
 
 	for (auto &file : fileList) {
-		// We will only process zip files for now
-		if (!file.getPath().baseName().matchString("*.zip", true))
-			continue;
-
 		td.name.clear();
+		bool isUnpackedTheme = false;
+		if (!file.getPath().baseName().matchString("*.zip", true)) {
+
+			// 2. If it's NOT a zip, check if it's a directory with a THEMERC file
+			if (file.isDirectory()) {
+				Common::FSNode themercNode = file.getChild("THEMERC");
+				if (themercNode.exists() && !themercNode.isDirectory()) {
+					isUnpackedTheme = true;
+				} else {
+					continue; // Not a zip, and no THEMERC found. Skip.
+				}
+			} else {
+				continue; // Not a zip, and not a directory. Skip.
+			}
+		}
+
 		if (themeConfigUsable(file, td.name)) {
 			td.filename = file.getPath();
 			td.id = file.getName();
 
 			// If the name of the node object also contains
 			// the ".zip" suffix, we will strip it.
-			if (td.id.matchString("*.zip", true)) {
+			if (isUnpackedTheme) {
+				td.id += "-unpacked";
+				td.name += " (unpacked)";
+			} else if (td.id.matchString("*.zip", true)) {
 				for (int j = 0; j < 4; ++j)
 					td.id.deleteLastChar();
 			}
@@ -2148,7 +2221,11 @@ Common::String ThemeEngine::getThemeId(const Common::Path &filename) {
 
 			return id;
 		} else {
-			return node.getName();
+			// unpacked theme we need to update the name with -unpacked
+			Common::String id = node.getName();
+			id.chop(1);
+			id += "-unpacked";
+			return id;
 		}
 	}
 
diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h
index 88c8abd3570..a60171fe094 100644
--- a/gui/ThemeEngine.h
+++ b/gui/ThemeEngine.h
@@ -750,6 +750,8 @@ private:
 	static void listUsableThemes(const Common::FSNode &node, Common::List<ThemeDescriptor> &list, int depth = -1);
 	static void listUsableThemes(Common::Archive &archive, Common::List<ThemeDescriptor> &list);
 
+	Common::Archive *createUnpackedThemeArchive(const Common::FSNode &themeDir);
+
 protected:
 	OSystem *_system; /** Global system object. */
 




More information about the Scummvm-git-logs mailing list