[Scummvm-git-logs] scummvm master -> bbc58f2b47eaca226b43cf7932429fe2fb603833

sev- noreply at scummvm.org
Mon Jun 1 18:06:37 UTC 2026


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

Summary:
0da70bcde1 DIRECTOR: Draw directToStage video in trails mode
682cd5f167 DIRECTOR: Fix invalid pointer in TextCastMember::writeSTXTResource
37fb0a2719 DIRECTOR: Add array guardrails in Movie::loadFileInfo
298b520c93 DIRECTOR: Manage all Archive lifetimes with SharePtr
53ac0b7ff3 DIRECTOR: Add Xtra + quirks for Pink Gear Collection
5085f88e77 DIRECTOR: Add guardrail to Symbol::operator==
9c211c8ff8 DIRECTOR: Improve accuracy of b_dontPassEvent
ff813b5efc DIRECTOR: Clear window modal flag in destructor
bbc58f2b47 DIRECTOR: Comment out crash-inducing movie export debug code


Commit: 0da70bcde1f0eb652afe66c1b5295bae102112b9
    https://github.com/scummvm/scummvm/commit/0da70bcde1f0eb652afe66c1b5295bae102112b9
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Draw directToStage video in trails mode

Fixes rendering of title movie in Mean City.

Changed paths:
    engines/director/channel.cpp


diff --git a/engines/director/channel.cpp b/engines/director/channel.cpp
index 6e4bf08d985..2d5b3936faa 100644
--- a/engines/director/channel.cpp
+++ b/engines/director/channel.cpp
@@ -757,7 +757,9 @@ bool Channel::updateWidget() {
 }
 
 bool Channel::isTrail() {
-	return _sprite->_trails;
+	return _sprite->_trails || (_sprite->_cast &&
+			(_sprite->_cast->_type == kCastDigitalVideo) &&
+			(((DigitalVideoCastMember *)_sprite->_cast)->_directToStage));
 }
 
 int Channel::getMouseChar(int x, int y) {


Commit: 682cd5f167b2cfaecd39147b9e361ded492e4409
    https://github.com/scummvm/scummvm/commit/682cd5f167b2cfaecd39147b9e361ded492e4409
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Fix invalid pointer in TextCastMember::writeSTXTResource

Changed paths:
    engines/director/castmember/text.cpp


diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index 368843d0dca..35ed292e400 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -1046,7 +1046,8 @@ uint32 TextCastMember::writeSTXTResource(Common::SeekableWriteStream *writeStrea
 				// Ignoring height and ascent for now from FontStyle
 				uint16 temp;
 				style.formatStartOffset = pIndex;
-				const Common::u32char_type_t *s = _ftext.substr(it, 22).c_str();
+				Common::U32String data = _ftext.substr(it, 22);
+				const Common::u32char_type_t *s = data.c_str();
 
 				s = Graphics::readHex(&style.fontId, s, 4);
 				s = Graphics::readHex(&temp, s, 2);


Commit: 37fb0a2719e52951a6603a7d529d0e82165c7545
    https://github.com/scummvm/scummvm/commit/37fb0a2719e52951a6603a7d529d0e82165c7545
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Add array guardrails in Movie::loadFileInfo

Changed paths:
    engines/director/movie.cpp


diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index 0d644f9146f..edea2f6e335 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -369,7 +369,8 @@ void Movie::loadFileInfo(Common::SeekableReadStreamEndian &stream) {
 	_allowOutdatedLingo = (fileInfo.flags & kMovieFlagAllowOutdatedLingo) != 0;
 	_remapPalettesWhenNeeded = (fileInfo.flags & kMovieFlagRemapPalettesWhenNeeded) != 0;
 
-	_script = fileInfo.strings[0].readString(false);
+	if (fileInfo.strings.size() >= 1)
+		_script = fileInfo.strings[0].readString(false);
 
 	if (!_script.empty() && ConfMan.getBool("dump_scripts"))
 		_cast->dumpScript(_script.c_str(), kMovieScript, 0);
@@ -377,12 +378,15 @@ void Movie::loadFileInfo(Common::SeekableReadStreamEndian &stream) {
 	if (!_script.empty())
 		_cast->_lingoArchive->addCode(_script, kMovieScript, 0, nullptr, kLPPTrimGarbage);
 
-	_changedBy = fileInfo.strings[1].readString();
-	_createdBy = fileInfo.strings[2].readString();
-	_origDirectory = fileInfo.strings[3].readString();
+	if (fileInfo.strings.size() >= 2)
+		_changedBy = fileInfo.strings[1].readString();
+	if (fileInfo.strings.size() >= 3)
+		_createdBy = fileInfo.strings[2].readString();
+	if (fileInfo.strings.size() >= 4)
+		_origDirectory = fileInfo.strings[3].readString();
 
 	uint16 preload = 0;
-	if (fileInfo.strings[4].len) {
+	if ((fileInfo.strings.size() >= 5) && fileInfo.strings[4].len) {
 		if (stream.isBE())
 			preload = READ_BE_INT16(fileInfo.strings[4].data);
 		else


Commit: 298b520c933c3cafb9a2e3ce9be83e72f2548ca5
    https://github.com/scummvm/scummvm/commit/298b520c933c3cafb9a2e3ce9be83e72f2548ca5
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Manage all Archive lifetimes with SharePtr

For various reasons we need to keep Archives around across movie
changes and multiple windows (e.g. shared casts). Easiest way to deal
with the lifetimes is to reference count them, and the easiest way to
reference count them is to use SharedPtr.

Fixes missing toolbox lower window in Opera Fatal.

Changed paths:
    engines/director/cast.cpp
    engines/director/cast.h
    engines/director/castmember/palette.cpp
    engines/director/cursor.cpp
    engines/director/debugger.cpp
    engines/director/debugger/dt-lists.cpp
    engines/director/director.cpp
    engines/director/director.h
    engines/director/lingo/lingo-builtins.cpp
    engines/director/movie.cpp
    engines/director/movie.h
    engines/director/resource.cpp
    engines/director/sound.cpp
    engines/director/tests.cpp
    engines/director/window.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index 6739fd58afe..ef9b52d450d 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -303,7 +303,7 @@ bool Cast::eraseCastMember(int castId) {
 	return false;
 }
 
-void Cast::setArchive(Archive *archive) {
+void Cast::setArchive(Common::SharedPtr<Archive> archive) {
 	_castArchive = archive;
 
 	if (archive->hasResource(MKTAG('M', 'C', 'N', 'M'), 0)) {
diff --git a/engines/director/cast.h b/engines/director/cast.h
index 5eeef4221ea..6005bdd3562 100644
--- a/engines/director/cast.h
+++ b/engines/director/cast.h
@@ -90,8 +90,8 @@ public:
 	~Cast();
 
 	void loadArchive();
-	void setArchive(Archive *archive);
-	Archive *getArchive() const { return _castArchive; };
+	void setArchive(Common::SharedPtr<Archive> archive);
+	Common::SharedPtr<Archive> getArchive() const { return _castArchive; };
 	Common::String getMacName() const { return _macName; }
 	Common::String getCastName() const { return _castName; }
 	void setCastName(const Common::String &name) { _castName = name; }
@@ -158,7 +158,7 @@ private:
 	uint32 computeChecksum();
 
 public:
-	Archive *_castArchive;
+	Common::SharedPtr<Archive> _castArchive;
 	Common::Platform _platform;
 	uint16 _castLibID;
 	uint16 _libResourceId;
diff --git a/engines/director/castmember/palette.cpp b/engines/director/castmember/palette.cpp
index 83bb0892abd..0a59f067cd5 100644
--- a/engines/director/castmember/palette.cpp
+++ b/engines/director/castmember/palette.cpp
@@ -114,7 +114,7 @@ void PaletteCastMember::load() {
 	if (paletteId) {
 
 		uint32 tag = MKTAG('C', 'L', 'U', 'T');
-		Archive *arch = _cast->getArchive();
+		Archive *arch = _cast->getArchive().get();
 		if (arch->hasResource(tag, paletteId)) {
 			Common::SeekableReadStreamEndian *pal = arch->getResource(MKTAG('C', 'L', 'U', 'T'), paletteId);
 			debugC(2, kDebugImages, "PaletteCastMember::load(): linking palette id %d to cast index %d", paletteId, _castId);
diff --git a/engines/director/cursor.cpp b/engines/director/cursor.cpp
index 30fc64ea802..0738a2c35ac 100644
--- a/engines/director/cursor.cpp
+++ b/engines/director/cursor.cpp
@@ -215,13 +215,13 @@ void Cursor::readFromResource(Datum resourceId) {
 
 		Cast *cast = g_director->getCurrentMovie()->getCast();
 		if (cast && cast->getArchive()) {
-			readSuccessful = readFromArchive(cast->getArchive(), resourceId.asInt());
+			readSuccessful = readFromArchive(cast->getArchive().get(), resourceId.asInt());
 			if (readSuccessful)
 				break;
 		}
 
 		for (auto &it : g_director->_allOpenResFiles) {
-			readSuccessful = readFromArchive(g_director->_allSeenResFiles[it], resourceId.asInt());
+			readSuccessful = readFromArchive(g_director->_allSeenResFiles[it].get(), resourceId.asInt());
 			if (readSuccessful)
 				break;
 		}
@@ -229,7 +229,7 @@ void Cursor::readFromResource(Datum resourceId) {
 		// Cursors can be located in the main archive, which may not
 		// be in _allOpenResFiles
 		if (!readSuccessful && g_director->getPlatform() == Common::kPlatformMacintosh) {
-			readSuccessful = readFromArchive(g_director->getMainArchive(), resourceId.asInt());
+			readSuccessful = readFromArchive(g_director->getMainArchive().get(), resourceId.asInt());
 		}
 
 		// TODO: figure out where to read custom cursor in windows platform
diff --git a/engines/director/debugger.cpp b/engines/director/debugger.cpp
index 48223247e48..a7d346ac083 100644
--- a/engines/director/debugger.cpp
+++ b/engines/director/debugger.cpp
@@ -273,7 +273,7 @@ bool Debugger::cmdVersion(int argc, const char **argv) {
 bool Debugger::cmdInfo(int argc, const char **argv) {
 	Movie *movie = g_director->getCurrentMovie();
 	Score *score = movie->getScore();
-	Archive *archive = movie->getArchive();
+	Archive *archive = movie->getArchive().get();
 	Cast *cast = movie->getCast();
 	debugPrintf("Movie path: %s\n", archive->getPathName().toString(g_director->_dirSeparator).c_str());
 	debugPrintf("Movie file size: %d\n", archive->getFileSize());
diff --git a/engines/director/debugger/dt-lists.cpp b/engines/director/debugger/dt-lists.cpp
index f6eb6018138..a88aecd4615 100644
--- a/engines/director/debugger/dt-lists.cpp
+++ b/engines/director/debugger/dt-lists.cpp
@@ -297,7 +297,7 @@ void showArchive() {
 			ImGui::BeginChild("ChildL", ImVec2(ImGui::GetContentRegionAvail().x * 0.3f, ImGui::GetContentRegionAvail().y), ImGuiChildFlags_None);
 
 			for (auto &it : g_director->_allSeenResFiles) {
-				Archive *archive = it._value;
+				Archive *archive = it._value.get();
 
 				if (ImGui::TreeNode(archive->getPathName().toString().c_str())) {
 					Common::Array<uint32> typeList = archive->getResourceTypeList();
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index e8de3dbd040..fdc65339d5f 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -181,9 +181,7 @@ DirectorEngine::~DirectorEngine() {
 		_currentWindow = nullptr;
 	}
 	delete _wm;
-	for (auto &it : _allSeenResFiles) {
-		delete it._value;
-	}
+	_allSeenResFiles.clear();
 	for (uint i = 0; i < _winCursor.size(); i++)
 		delete _winCursor[i];
 
diff --git a/engines/director/director.h b/engines/director/director.h
index 0d4d2fbbe2a..6c83e8a7110 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -186,8 +186,8 @@ public:
 	void setCursorWindow(Window *window) { _cursorWindow = window; }
 	Movie *getCurrentMovie() const;
 	void setCurrentMovie(Movie *movie);
-	Archive *getMainArchive() const { return _mainArchive; }
-	void setMainArchive(Archive *archive) { _mainArchive = archive; }
+	Common::SharedPtr<Archive> getMainArchive() const { return _mainArchive; }
+	void setMainArchive(Common::SharedPtr<Archive> archive) { _mainArchive = archive; }
 	Common::String getCurrentPath() const;
 	Common::String getCurrentAbsolutePath();
 	Common::Path getStartupPath() const;
@@ -230,7 +230,7 @@ public:
 	Common::CodePage getPlatformEncoding();
 
 	Archive *createArchive();
-	Archive *openArchive(const Common::Path &movie);
+	Common::SharedPtr<Archive> openArchive(const Common::Path &movie);
 	void addArchiveToOpenList(const Common::Path &path);
 	Archive *loadEXE(const Common::Path &movie);
 	Archive *loadEXEv3(Common::SeekableReadStream *stream);
@@ -271,15 +271,15 @@ public:
 	bool _centerStage;
 	char _dirSeparator;
 	bool _fixStageSize;
-	Archive *_mainArchive;
+	Common::SharedPtr<Archive> _mainArchive;
 	Common::Rect _fixStageRect;
 	Common::List<Common::String> _extraSearchPath;
 	bool _emulateMultiButtonMouse;
 
 	// Owner of all Archive objects.
-	Common::HashMap<Common::Path, Archive *, Common::Path::IgnoreCaseAndMac_Hash, Common::Path::IgnoreCaseAndMac_EqualTo> _allSeenResFiles;
+	Common::HashMap<Common::Path, Common::SharedPtr<Archive>, Common::Path::IgnoreCaseAndMac_Hash, Common::Path::IgnoreCaseAndMac_EqualTo> _allSeenResFiles;
 	// Handles to resource files that were opened by OpenResFile.
-	Common::HashMap<Common::Path, Archive *, Common::Path::IgnoreCaseAndMac_Hash, Common::Path::IgnoreCaseAndMac_EqualTo> _openResFiles;
+	Common::HashMap<Common::Path, Common::SharedPtr<Archive>, Common::Path::IgnoreCaseAndMac_Hash, Common::Path::IgnoreCaseAndMac_EqualTo> _openResFiles;
 	// List of all currently open resource files
 	Common::List<Common::Path> _allOpenResFiles;
 
diff --git a/engines/director/lingo/lingo-builtins.cpp b/engines/director/lingo/lingo-builtins.cpp
index de210df178c..98924a725a6 100644
--- a/engines/director/lingo/lingo-builtins.cpp
+++ b/engines/director/lingo/lingo-builtins.cpp
@@ -1806,13 +1806,11 @@ void LB::b_openResFile(int nargs) {
  	}
 
 	if (!g_director->_allSeenResFiles.contains(resPath)) {
-		MacArchive *arch = new MacArchive();
+		Common::SharedPtr<Archive> arch(new MacArchive());
 		if (arch->openFile(findPath(resPath))) {
 			g_director->_openResFiles.setVal(resPath, arch);
 			g_director->_allSeenResFiles.setVal(resPath, arch);
 			g_director->addArchiveToOpenList(resPath);
-		} else {
-			delete arch;
 		}
 	}
 }
diff --git a/engines/director/movie.cpp b/engines/director/movie.cpp
index edea2f6e335..218e12f5906 100644
--- a/engines/director/movie.cpp
+++ b/engines/director/movie.cpp
@@ -117,7 +117,7 @@ Movie::~Movie() {
 	delete _score;
 }
 
-void Movie::setArchive(Archive *archive) {
+void Movie::setArchive(Common::SharedPtr<Archive> archive) {
 	_movieArchive = archive;
 
 	if (archive->hasResource(MKTAG('M', 'C', 'N', 'M'), 0)) {
@@ -169,7 +169,7 @@ void Movie::loadCastLibMapping(Common::SeekableReadStreamEndian &stream) {
 		uint16 libResourceId = stream.readUint16();
 		uint16 libId = i + 1;
 		debugC(5, kDebugLoading, "Movie::loadCastLibMapping: name: %s, path: %s, minMember: %d, maxMember: %d, libResourceId: %d, libId: %d", utf8ToPrintable(name).c_str(), utf8ToPrintable(path).c_str(), minMember, maxMember, libResourceId, libId);
-		Archive *castArchive = _movieArchive;
+		Common::SharedPtr<Archive> castArchive = _movieArchive;
 		bool isExternal = !path.empty();
 		if (isExternal) {
 			Common::Path archivePath = findMoviePath(path);
@@ -424,7 +424,7 @@ void Movie::clearSharedCast() {
 void Movie::loadSharedCastsFrom(Common::Path &filename) {
 	clearSharedCast();
 
-	Archive *sharedCast = _vm->openArchive(filename);
+	Common::SharedPtr<Archive> sharedCast = _vm->openArchive(filename);
 
 	if (!sharedCast) {
 		warning("loadSharedCastsFrom(): No shared cast %s", filename.toString().c_str());
@@ -442,8 +442,8 @@ void Movie::loadSharedCastsFrom(Common::Path &filename) {
 	_sharedCast->loadArchive();
 }
 
-Archive *Movie::loadExternalCastFrom(Common::Path &filename) {
-	Archive *externalCast = nullptr;
+Common::SharedPtr<Archive> Movie::loadExternalCastFrom(Common::Path &filename) {
+	Common::SharedPtr<Archive> externalCast = nullptr;
 	externalCast = _vm->openArchive(filename);
 
 	if (!externalCast) {
@@ -468,7 +468,7 @@ bool Movie::loadCastLibFrom(uint16 libId, Common::Path &filename) {
 		}
 	}
 
-	Archive *castArchive = loadExternalCastFrom(filename);
+	Common::SharedPtr<Archive> castArchive = loadExternalCastFrom(filename);
 	if (!castArchive) {
 		return false;
 	}
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 5640c6d6f64..5aee2c30f2c 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -98,8 +98,8 @@ public:
 
 	void loadCastLibMapping(Common::SeekableReadStreamEndian &stream);
 	bool loadArchive();
-	void setArchive(Archive *archive);
-	Archive *getArchive() const { return _movieArchive; };
+	void setArchive(Common::SharedPtr<Archive> archive);
+	Common::SharedPtr<Archive> getArchive() const { return _movieArchive; };
 	Common::String getMacName() const { return _macName; }
 	Window *getWindow() const { return _window; }
 	DirectorEngine *getVM() const { return _vm; }
@@ -112,7 +112,7 @@ public:
 
 	void clearSharedCast();
 	void loadSharedCastsFrom(Common::Path &filename);
-	Archive *loadExternalCastFrom(Common::Path &filename);
+	Common::SharedPtr<Archive> loadExternalCastFrom(Common::Path &filename);
 	bool loadCastLibFrom(uint16 libId, Common::Path &filename);
 
 	CastMember *getCastMember(CastMemberID memberID);
@@ -153,7 +153,7 @@ private:
 	void queueSpriteEvent(Common::Queue<LingoEvent> &queue, LEvent event, int eventId, int spriteId);
 
 public:
-	Archive *_movieArchive;
+	Common::SharedPtr<Archive> _movieArchive;
 	uint16 _version;
 	Common::Platform _platform;
 	Common::Rect _movieRect;
diff --git a/engines/director/resource.cpp b/engines/director/resource.cpp
index 5dade0314fb..ca9e4961ffb 100644
--- a/engines/director/resource.cpp
+++ b/engines/director/resource.cpp
@@ -67,14 +67,14 @@ Common::Error Window::loadInitialMovie() {
 	}
 	loadINIStream();
 	Common::Path path = findPath(movie);
-	Archive *mainArchive = g_director->openArchive(path);
+	Common::SharedPtr<Archive> mainArchive = g_director->openArchive(path);
 
 	if (!mainArchive) {
 		warning("Window::loadInitialMovie: Cannot open main movie");
 		return Common::kNoGameDataFoundError;
 	}
 	g_director->setMainArchive(mainArchive);
-	probeResources(mainArchive);
+	probeResources(mainArchive.get());
 
 	// Load multiple-resources based executable file (Projector)
 	Common::String rawEXE = _vm->getRawEXEName();
@@ -163,8 +163,8 @@ void Window::probeResources(Archive *archive) {
 		}
 
 		if (archive->hasResource(MKTAG('S', 'T', 'R', '#'), 0)) {
-			if (_currentMovie)
-				_currentMovie->setArchive(archive);
+			//if (_currentMovie)
+			//	_currentMovie->setArchive(archive);
 
 			Common::SeekableReadStreamEndian *name = archive->getResource(MKTAG('S', 'T', 'R', '#'), 0);
 			int num = name->readUint16();
@@ -186,9 +186,9 @@ void Window::probeResources(Archive *archive) {
 					_currentMovie = nullptr;
 				}
 
-				Archive *subMovie = g_director->openArchive(moviePath);
+				Common::SharedPtr<Archive> subMovie = g_director->openArchive(moviePath);
 				if (subMovie) {
-					probeResources(subMovie);
+					probeResources(subMovie.get());
 				}
 			} else {
 				warning("Window::probeResources: Couldn't find score with name: %s", sname.c_str());
@@ -244,7 +244,7 @@ void DirectorEngine::addArchiveToOpenList(const Common::Path &path) {
 	_allOpenResFiles.push_front(path);
 }
 
-Archive *DirectorEngine::openArchive(const Common::Path &path) {
+Common::SharedPtr<Archive> DirectorEngine::openArchive(const Common::Path &path) {
 	debug(1, "DirectorEngine::openArchive(\"%s\")", path.toString().c_str());
 
 	// If the archive is already open, don't reopen it;
@@ -269,11 +269,12 @@ Archive *DirectorEngine::openArchive(const Common::Path &path) {
 		}
 	}
 	result->setPathName(path);
-	_allSeenResFiles.setVal(path, result);
+	Common::SharedPtr<Archive> arch(result);
+	_allSeenResFiles.setVal(path, arch);
 
 	addArchiveToOpenList(path);
 
-	return result;
+	return arch;
 }
 
 void Window::loadINIStream() {
diff --git a/engines/director/sound.cpp b/engines/director/sound.cpp
index b8b03a25698..47672584184 100644
--- a/engines/director/sound.cpp
+++ b/engines/director/sound.cpp
@@ -400,7 +400,7 @@ void DirectorSound::loadSampleSounds(uint type) {
 		for (uint j = 0; j < idList.size(); j++) {
 			if (static_cast<uint>(idList[j] & 0xFF) == type) {
 				id = idList[j];
-				archive = g_director->_allSeenResFiles[it];
+				archive = g_director->_allSeenResFiles[it].get();
 				break;
 			}
 		}
@@ -637,7 +637,7 @@ void DirectorSound::playFPlaySound() {
 	for (auto &it : g_director->_allOpenResFiles) {
 		id = g_director->_allSeenResFiles[it]->findResourceID(tag, sndName, true);
 		if (id != 0xFFFF) {
-			archive = g_director->_allSeenResFiles[it];
+			archive = g_director->_allSeenResFiles[it].get();
 			break;
 		}
 	}
diff --git a/engines/director/tests.cpp b/engines/director/tests.cpp
index cfb6d5aacab..ad7ea478d5a 100644
--- a/engines/director/tests.cpp
+++ b/engines/director/tests.cpp
@@ -193,7 +193,7 @@ Common::HashMap<Common::String, Movie *> *Window::scanMovies(const Common::Path
 			}
 
 			warning("name: %s", i->getName().c_str());
-			Archive *arc = _vm->openArchive(i->getPathInArchive());
+			Common::SharedPtr<Archive> arc = _vm->openArchive(i->getPathInArchive());
 			Movie *m = new Movie(this);
 			m->setArchive(arc);
 			nameMap->setVal(m->getMacName(), m);
@@ -324,7 +324,7 @@ void Window::runTests() {
 
 	initGraphics(640, 480);
 
-	Archive *mainArchive = new RIFXArchive();
+	Common::SharedPtr<Archive> mainArchive(new RIFXArchive());
 	g_director->setMainArchive(mainArchive);
 	g_director->_allSeenResFiles.setVal("test.dir", mainArchive);
 	if (!mainArchive->openStream(stream, 0)) {
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index c6af79c18f9..9602f3e4e6f 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -561,7 +561,6 @@ void Window::loadNewSharedCast(Cast *previousSharedCast) {
 
 		g_director->_allSeenResFiles.erase(previousSharedCastPath);
 		g_director->_allOpenResFiles.remove(previousSharedCastPath);
-		delete previousSharedCast->_castArchive;
 		delete previousSharedCast;
 	} else {
 		debug(0, "@@   No previous shared cast");
@@ -600,14 +599,14 @@ bool Window::loadNextMovie() {
 		_currentMovie = nullptr;
 	}
 
-	Archive *mov = g_director->openArchive(archivePath);
+	Common::SharedPtr<Archive> mov = g_director->openArchive(archivePath);
 
 	_nextMovie.movie.clear(); // Clearing it, so we will not attempt to load again
 
 	if (!mov)
 		return false;
 
-	probeResources(mov);
+	probeResources(mov.get());
 
 	// Artificial delay for games that expect slow media, e.g. Spaceship Warlock
 	if (g_director->_loadSlowdownFactor && !debugChannelSet(-1, kDebugFast)) {


Commit: 53ac0b7ff382b1bf95e3c3e12d27b4ffb3267238
    https://github.com/scummvm/scummvm/commit/53ac0b7ff382b1bf95e3c3e12d27b4ffb3267238
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Add Xtra + quirks for Pink Gear Collection

Changed paths:
  A engines/director/lingo/xtras/g/getdir.cpp
  A engines/director/lingo/xtras/g/getdir.h
    engines/director/game-quirks.cpp
    engines/director/lingo/lingo-object.cpp
    engines/director/module.mk


diff --git a/engines/director/game-quirks.cpp b/engines/director/game-quirks.cpp
index ecd6081eff5..26601391c4e 100644
--- a/engines/director/game-quirks.cpp
+++ b/engines/director/game-quirks.cpp
@@ -312,6 +312,10 @@ const struct Quirk {
 	{ "puppetmotel", Common::kPlatformWindows, &quirkForceFileIOXtra },
 	{ "puppetmotel", Common::kPlatformMacintosh, &quirkForceFileIOXtra },
 
+	// Pink Gear Collection uses the Xtra version, but loads it manually with openXLib.
+	{ "pinkgear", Common::kPlatformWindows, &quirkForceFileIOXtra },
+	{ "pinkgear", Common::kPlatformMacintosh, &quirkForceFileIOXtra },
+
 	// Stay Tooned is D5, but expects the XObject version to be used.
 	{ "staytooned", Common::kPlatformWindows, &quirkForceFileIOXObj },
 	{ "staytooned", Common::kPlatformMacintosh, &quirkForceFileIOXObj },
diff --git a/engines/director/lingo/lingo-object.cpp b/engines/director/lingo/lingo-object.cpp
index 40ca497c2d0..5f6193c1e23 100644
--- a/engines/director/lingo/lingo-object.cpp
+++ b/engines/director/lingo/lingo-object.cpp
@@ -156,6 +156,7 @@
 #include "director/lingo/xtras/d/directsound.h"
 #include "director/lingo/xtras/d/displayres.h"
 #include "director/lingo/xtras/f/filextra.h"
+#include "director/lingo/xtras/g/getdir.h"
 #include "director/lingo/xtras/k/keypoll.h"
 #include "director/lingo/xtras/m/masterapp.h"
 #include "director/lingo/xtras/m/mui.h"
@@ -297,6 +298,7 @@ static const struct XLibProto {
 	XLIBDEF(FlushXObj,			kXObj,			300),	// D3
 	XLIBDEF(FPlayXObj,			kXObj,			200),	// D2
 	XLIBDEF(GenUtilsXObj,		kXObj,			400),	// D4
+	XLIBDEF(GetDirXtra,			kXtraObj,					500),	// D5
 	XLIBDEF(GetScreenRectsXFCN,	kXObj,			300),	// D3
 	XLIBDEF(GetScreenSizeXFCN,	kXObj,			300),	// D3
 	XLIBDEF(GetSoundInLevelXObj,kXObj,			400),	// D4
diff --git a/engines/director/lingo/xtras/g/getdir.cpp b/engines/director/lingo/xtras/g/getdir.cpp
new file mode 100644
index 00000000000..431be2a627d
--- /dev/null
+++ b/engines/director/lingo/xtras/g/getdir.cpp
@@ -0,0 +1,118 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "common/system.h"
+
+#include "director/director.h"
+#include "director/lingo/lingo.h"
+#include "director/lingo/lingo-object.h"
+#include "director/lingo/lingo-utils.h"
+#include "director/lingo/xtras/g/getdir.h"
+
+/**************************************************
+ *
+ * USED IN:
+ * pinkgear
+ *
+ **************************************************/
+
+/*
+-- xtra GetDir
+new object me
+forget object me
+-- GetDirXtra --
+GetDirOne object me, int repeat -- GetDir n times using default system GetDir
+* GetDirTwo -- global level GetDir method: GetDirs once
++ GetDirThree  object xtraRef -- xtra level version of above method
+* GetWindowsDir -- return path to windows directory
+* GetSystemDir -- return path to windows system directory
+
+ */
+
+namespace Director {
+
+const char *GetDirXtra::xlibName = "GetDir";
+const XlibFileDesc GetDirXtra::fileNames[] = {
+	{ "getdir",   nullptr },
+	{ nullptr,        nullptr },
+};
+
+static MethodProto xlibMethods[] = {
+	{ "new",				GetDirXtra::m_new,		 0, 0,	500 },
+	{ "forget",				GetDirXtra::m_forget,		 0, 0,	500 },
+	{ "GetDirOne",				GetDirXtra::m_GetDirOne,		 1, 1,	500 },
+	{ "GetDirThree",				GetDirXtra::m_GetDirThree,		 0, 0,	500 },
+	{ nullptr, nullptr, 0, 0, 0 }
+};
+
+static BuiltinProto xlibBuiltins[] = {
+	{ "GetDirTwo", GetDirXtra::m_GetDirTwo, 0, 0, 500, HBLTIN },
+	{ "GetWindowsDir", GetDirXtra::m_GetWindowsDir, 0, 0, 500, HBLTIN },
+	{ "GetSystemDir", GetDirXtra::m_GetSystemDir, 0, 0, 500, HBLTIN },
+	{ nullptr, nullptr, 0, 0, 0, VOIDSYM }
+};
+
+GetDirXtraObject::GetDirXtraObject(ObjectType ObjectType) :Object<GetDirXtraObject>("GetDir") {
+	_objType = ObjectType;
+}
+
+bool GetDirXtraObject::hasProp(const Common::String &propName) {
+	return (propName == "name");
+}
+
+Datum GetDirXtraObject::getProp(const Common::String &propName) {
+	if (propName == "name")
+		return Datum(GetDirXtra::xlibName);
+	warning("GetDirXtra::getProp: unknown property '%s'", propName.c_str());
+	return Datum();
+}
+
+void GetDirXtra::open(ObjectType type, const Common::Path &path) {
+    GetDirXtraObject::initMethods(xlibMethods);
+    GetDirXtraObject *xobj = new GetDirXtraObject(type);
+    if (type == kXtraObj) {
+        g_lingo->_openXtras.push_back(xlibName);
+		g_lingo->_openXtraObjects.push_back(xobj);
+	}
+    g_lingo->exposeXObject(xlibName, xobj);
+    g_lingo->initBuiltIns(xlibBuiltins);
+}
+
+void GetDirXtra::close(ObjectType type) {
+    GetDirXtraObject::cleanupMethods();
+    g_lingo->_globalvars[xlibName] = Datum();
+
+}
+
+void GetDirXtra::m_new(int nargs) {
+	g_lingo->printSTUBWithArglist("GetDirXtra::m_new", nargs);
+	g_lingo->dropStack(nargs);
+	g_lingo->push(g_lingo->_state->me);
+}
+
+XOBJSTUB(GetDirXtra::m_forget, 0)
+XOBJSTUB(GetDirXtra::m_GetDirOne, 0)
+XOBJSTUB(GetDirXtra::m_GetDirTwo, 0)
+XOBJSTUB(GetDirXtra::m_GetDirThree, 0)
+XOBJSTUB(GetDirXtra::m_GetWindowsDir, Datum("C:\\"))
+XOBJSTUB(GetDirXtra::m_GetSystemDir, Datum("@:"))
+
+}
diff --git a/engines/director/lingo/xtras/g/getdir.h b/engines/director/lingo/xtras/g/getdir.h
new file mode 100644
index 00000000000..a75db96d1c6
--- /dev/null
+++ b/engines/director/lingo/xtras/g/getdir.h
@@ -0,0 +1,55 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DIRECTOR_LINGO_XTRAS_G_GETDIR_H
+#define DIRECTOR_LINGO_XTRAS_G_GETDIR_H
+
+namespace Director {
+
+class GetDirXtraObject : public Object<GetDirXtraObject> {
+public:
+	GetDirXtraObject(ObjectType objType);
+
+	bool hasProp(const Common::String &propName) override;
+	Datum getProp(const Common::String &propName) override;
+};
+
+namespace GetDirXtra {
+
+extern const char *xlibName;
+extern const XlibFileDesc fileNames[];
+
+void open(ObjectType type, const Common::Path &path);
+void close(ObjectType type);
+
+void m_new(int nargs);
+void m_forget(int nargs);
+void m_GetDirOne(int nargs);
+void m_GetDirTwo(int nargs);
+void m_GetDirThree(int nargs);
+void m_GetWindowsDir(int nargs);
+void m_GetSystemDir(int nargs);
+
+} // End of namespace GetDirXtra
+
+} // End of namespace Director
+
+#endif
diff --git a/engines/director/module.mk b/engines/director/module.mk
index 0f70a1b434d..2b460e50677 100644
--- a/engines/director/module.mk
+++ b/engines/director/module.mk
@@ -191,6 +191,7 @@ MODULE_OBJS = \
 	lingo/xtras/k/keypoll.o \
 	lingo/xtras/m/masterapp.o \
 	lingo/xtras/m/mui.o \
+	lingo/xtras/g/getdir.o \
 	lingo/xtras/o/openurl.o \
 	lingo/xtras/o/oscheck.o \
 	lingo/xtras/q/qtvrxtra.o \


Commit: 5085f88e77957525a7fdd82f5e91c6502ae81be4
    https://github.com/scummvm/scummvm/commit/5085f88e77957525a7fdd82f5e91c6502ae81be4
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Add guardrail to Symbol::operator==

Changed paths:
    engines/director/lingo/lingo.cpp


diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index b6327fc6b09..db54113b73d 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -109,6 +109,10 @@ Symbol& Symbol::operator=(const Symbol &s) {
 }
 
 bool Symbol::operator==(Symbol &s) const {
+	if ((s.type == VOIDSYM) && (type == VOIDSYM))
+		return true;
+	if ((!name || !s.name))
+		return false;
 	return ctx == s.ctx && (name->equalsIgnoreCase(*s.name));
 }
 


Commit: 9c211c8ff8913a84f18e728dedf78ed167c35a30
    https://github.com/scummvm/scummvm/commit/9c211c8ff8913a84f18e728dedf78ed167c35a30
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Improve accuracy of b_dontPassEvent

When fetching system input events, Director seems to process them
immediately (if possible) and use the value of the _passEvent flag
to determine if other widgets get the event. This means you can e.g.
set up a keyDownScript which calls dontPassEvent if Enter is pressed,
and the selected textbox won't receive that key.

If the system event queue is being accessed while another script is
executing, buffer the event for later like we did before.

Fixes overflowing the name textbox in Pink Gear Collection.

Changed paths:
    engines/director/castmember/text.cpp
    engines/director/director.cpp
    engines/director/director.h
    engines/director/events.cpp
    engines/director/lingo/lingo-events.cpp
    engines/director/lingo/lingo.cpp
    engines/director/movie.h
    engines/director/score.cpp
    engines/director/transitions.cpp
    engines/director/window.cpp
    engines/director/window.h
    graphics/macgui/macwindow.cpp


diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index 35ed292e400..06806dd8ecf 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -293,7 +293,7 @@ void TextCastMember::importStxt(const Stxt *stxt) {
 }
 
 bool textWindowCallback(Graphics::WindowClick click, Common::Event &event, void *ptr) {
-	return g_director->getCurrentMovie()->processEvent(event);
+	return g_director->getCurrentMovie()->processSysEvent(event);
 }
 
 Graphics::MacWidget *TextCastMember::createWindowOrWidget(Common::Rect &bbox, Common::Rect dims, Graphics::MacFont *macFont) {
diff --git a/engines/director/director.cpp b/engines/director/director.cpp
index fdc65339d5f..bd7afa3ea54 100644
--- a/engines/director/director.cpp
+++ b/engines/director/director.cpp
@@ -358,7 +358,7 @@ Common::Error DirectorEngine::run() {
 
 	while (loop) {
 		if (_stage->getCurrentMovie())
-			processEvents();
+			processSysEvents();
 
 		setCurrentWindow(_stage);
 		g_lingo->switchStateFromWindow();
diff --git a/engines/director/director.h b/engines/director/director.h
index 6c83e8a7110..b994db9b77d 100644
--- a/engines/director/director.h
+++ b/engines/director/director.h
@@ -244,7 +244,7 @@ public:
 
 	// events.cpp
 	bool pollEvent(Common::Event &event);
-	bool processEvents(bool captureClick = false, bool skipWindowManager = false);
+	bool processSysEvents(bool captureClick = false, bool skipWindowManager = false);
 	void processEventQUIT();
 	int getMacTicks();
 	Common::Array<Common::Event> _injectedEvents;
diff --git a/engines/director/events.cpp b/engines/director/events.cpp
index f0146900278..59db793449a 100644
--- a/engines/director/events.cpp
+++ b/engines/director/events.cpp
@@ -52,7 +52,7 @@ bool DirectorEngine::pollEvent(Common::Event &event) {
 	return g_system->getEventManager()->pollEvent(event);
 }
 
-bool DirectorEngine::processEvents(bool captureClick, bool skipWindowManager) {
+bool DirectorEngine::processSysEvents(bool captureClick, bool skipWindowManager) {
 	debugC(9, kDebugEvents, "\n@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
 	debugC(9, kDebugEvents, "@@@@   Processing events");
 	debugC(9, kDebugEvents, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
@@ -133,16 +133,25 @@ void DirectorEngine::processEventQUIT() {
 	}
 }
 
-bool Window::processEvent(Common::Event &event) {
+bool Window::processSysEvent(Common::Event &event) {
 	bool flag = false;
 
-	if (_currentMovie && _currentMovie->processEvent(event))
-		flag = true;
+	if (g_lingo) {
+		Window *prev = g_director->getCurrentWindow();
+		g_director->setCurrentWindow(this);
+		g_lingo->switchStateFromWindow();
+
+		if (_currentMovie && _currentMovie->processSysEvent(event))
+			flag = true;
+
+		g_director->setCurrentWindow(prev);
+		g_lingo->switchStateFromWindow();
+	}
 
 	return flag;
 }
 
-bool Movie::processEvent(Common::Event &event) {
+bool Movie::processSysEvent(Common::Event &event) {
 	// When in GUI message box is being shown, movie may record clicking on the message box as a movie event
 	// Make sure that these events (mouseUp, mouseDown) are not recorded in the movie
 	if (_inGuiMessageBox) {
@@ -151,10 +160,11 @@ bool Movie::processEvent(Common::Event &event) {
 
 	Score *sc = getScore();
 	if (sc->getCurrentFrameNum() > sc->getFramesNum()) {
-		warning("processEvents: request to access frame %d of %d", sc->getCurrentFrameNum(), sc->getFramesNum());
+		warning("Movie::processSysEvent: request to access frame %d of %d", sc->getCurrentFrameNum(), sc->getFramesNum());
 		return false;
 	}
 	uint16 spriteId = 0;
+	bool result = true;
 
 	if (event.mouse != Common::Point(-1, -1)) {
 		if (g_director->getVersion() < 400)
@@ -235,7 +245,7 @@ bool Movie::processEvent(Common::Event &event) {
 				}
 			}
 		}
-		return true;
+		return result;
 
 	case Common::EVENT_LBUTTONDOWN:
 	case Common::EVENT_RBUTTONDOWN:
@@ -248,7 +258,7 @@ bool Movie::processEvent(Common::Event &event) {
 
 			if (g_director->getVersion() >= 600) {
 				if (_lastClickedSpriteId && _lastClickedSpriteId != spriteId) {
-					queueInputEvent(kEventMouseUpOutSide, _lastClickedSpriteId, pos);
+					processInputEvent(kEventMouseUpOutSide, _lastClickedSpriteId, pos);
 				}
 			}
 
@@ -276,24 +286,24 @@ bool Movie::processEvent(Common::Event &event) {
 				}
 			}
 
-			debugC(3, kDebugEvents, "Movie::processEvent(): Button Down @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
-			queueInputEvent(ev, 0, pos);
+			debugC(3, kDebugEvents, "Movie::processSysEvent(): Button Down @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
+			result = processInputEvent(ev, 0, pos);
 
 			// D5 has special behavior here
 			if (g_director->getVersion() >= 500 && g_director->getVersion() < 600) {
 				if (_lastClickedSpriteId)
-					queueInputEvent(kEventMouseEnter, _lastClickedSpriteId, pos);
+					processInputEvent(kEventMouseEnter, _lastClickedSpriteId, pos);
 			}
 		}
 
-		return true;
+		return result;
 
 	case Common::EVENT_LBUTTONUP:
 	case Common::EVENT_RBUTTONUP:
 		{
 			pos = event.mouse;
 
-			debugC(3, kDebugEvents, "Movie::processEvent(): Button Up @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
+			debugC(3, kDebugEvents, "Movie::processSysEvent(): Button Up @(%d, %d), movie '%s'", pos.x, pos.y, _macName.c_str());
 
 			LEvent ev = kEventMouseUp;
 			// In D5 and up, right mouse clicks don't trigger the mouseUp handler.
@@ -311,17 +321,17 @@ bool Movie::processEvent(Common::Event &event) {
 				}
 			}
 
-			queueInputEvent(ev, 0, pos);
+			result = processInputEvent(ev, 0, pos);
 
 			// D5 has special behavior here
 			if (g_director->getVersion() >= 500 && g_director->getVersion() < 600) {
 				if (spriteId)
-					queueInputEvent(kEventMouseLeave, spriteId, pos);
+					processInputEvent(kEventMouseLeave, spriteId, pos);
 			}
 
 			sc->renderCursor(pos);
 		}
-		return true;
+		return result;
 
 	case Common::EVENT_KEYDOWN:
 		_keyCode = _vm->_KeyCodes.contains(event.kbd.keycode) ? _vm->_KeyCodes[event.kbd.keycode] : 0;
@@ -361,14 +371,14 @@ bool Movie::processEvent(Common::Event &event) {
 		if (_timeOutKeyDown)
 			_lastTimeOut = _lastEventTime;
 
-		queueInputEvent(kEventKeyDown, sc->getSpriteIDOfActiveWidget());
+		result = processInputEvent(kEventKeyDown, sc->getSpriteIDOfActiveWidget());
 		g_director->loadSlowdownCooloff();
-		return true;
+		return result;
 
 	case Common::EVENT_KEYUP:
-		queueInputEvent(kEventKeyUp, sc->getSpriteIDOfActiveWidget());
+		result = processInputEvent(kEventKeyUp, sc->getSpriteIDOfActiveWidget());
 		_keyFlags = event.kbd.flags;
-		return true;
+		return result;
 
 	default:
 		break;
@@ -421,7 +431,7 @@ bool Window::processWMEvent(Graphics::WindowClick click, Common::Event &event) {
 		break;
 	}
 
-	flag |= processEvent(event);
+	flag |= processSysEvent(event);
 	return flag;
 }
 
diff --git a/engines/director/lingo/lingo-events.cpp b/engines/director/lingo/lingo-events.cpp
index a412dff3397..544ed07ac2e 100644
--- a/engines/director/lingo/lingo-events.cpp
+++ b/engines/director/lingo/lingo-events.cpp
@@ -611,6 +611,22 @@ void Movie::queueInputEvent(LEvent event, int targetId, Common::Point pos) {
 	queueEvent(_inputEventQueue, event, targetId, pos);
 }
 
+
+bool Movie::processInputEvent(LEvent event, int targetId, Common::Point pos) {
+	if (!_lingo->_state->callstack.empty()) {
+		// We're in the middle of executing something else, queue input event for later
+		queueInputEvent(event, targetId, pos);
+		return true;
+	}
+	// Try and process event inline
+	Common::Queue<LingoEvent> queue;
+	queueEvent(queue, event, targetId, pos);
+	_vm->setCurrentWindow(this->getWindow());
+	_lingo->processEvents(queue, true);
+	return _lingo->_passEvent;
+}
+
+
 void Movie::processEvent(LEvent event, int targetId) {
 	Common::Queue<LingoEvent> queue;
 	queueEvent(queue, event, targetId);
diff --git a/engines/director/lingo/lingo.cpp b/engines/director/lingo/lingo.cpp
index db54113b73d..d11bbe941ad 100644
--- a/engines/director/lingo/lingo.cpp
+++ b/engines/director/lingo/lingo.cpp
@@ -651,7 +651,7 @@ bool Lingo::execute(int targetFrame) {
 
 		// process events every so often
 		if (localCounter > 0 && localCounter % 100 == 0) {
-			_vm->processEvents();
+			_vm->processSysEvents();
 			// Also process update widgets!
 			Movie *movie = g_director->getCurrentMovie();
 			Score *score = movie->getScore();
diff --git a/engines/director/movie.h b/engines/director/movie.h
index 5aee2c30f2c..773c60262f6 100644
--- a/engines/director/movie.h
+++ b/engines/director/movie.h
@@ -135,7 +135,7 @@ public:
 	Symbol getHandler(const Common::String &name, uint16 castLibHint = 0);
 
 	// lingo/lingo-events.cpp
-	bool processEvent(Common::Event &event);
+	bool processSysEvent(Common::Event &event);
 	void broadcastEvent(LEvent event);
 
 	// lingo/lingo-events.cpp
@@ -143,6 +143,7 @@ public:
 	void resolveScriptEvent(LingoEvent &event);
 	void processEvent(LEvent event, int targetId = 0);
 	void queueInputEvent(LEvent event, int targetId = 0, Common::Point pos = Common::Point(-1, -1));
+	bool processInputEvent(LEvent event, int targetId = 0, Common::Point pos = Common::Point(-1, -1));
 
 	Common::String formatMovieInfo();
 
diff --git a/engines/director/score.cpp b/engines/director/score.cpp
index d922b220003..1465d21b7e6 100644
--- a/engines/director/score.cpp
+++ b/engines/director/score.cpp
@@ -124,7 +124,7 @@ void Score::setPuppetTempo(int16 puppetTempo) {
 }
 
 CastMemberID Score::getCurrentPalette() {
-	return g_director->_lastPalette;
+	return _vm->_lastPalette;
 }
 
 bool Score::processImmediateFrameScript(Common::String s, int id) {
@@ -353,11 +353,11 @@ void Score::step() {
 	update();
 
 	if (debugChannelSet(-1, kDebugFewFramesOnly) || debugChannelSet(-1, kDebugScreenshot)) {
-		warning("Score::startLoop(): ran frame %0d", g_director->_framesRan);
-		g_director->_framesRan++;
+		warning("Score::startLoop(): ran frame %0d", _vm->_framesRan);
+		_vm->_framesRan++;
 	}
 
-	if (debugChannelSet(-1, kDebugFewFramesOnly) && g_director->_framesRan > kFewFamesMaxCounter) {
+	if (debugChannelSet(-1, kDebugFewFramesOnly) && _vm->_framesRan > kFewFamesMaxCounter) {
 		warning("Score::startLoop(): exiting due to debug few frames only");
 		_playState = kPlayStopped;
 		return;
@@ -545,8 +545,8 @@ void Score::updateNextFrameTime() {
 			} else if (tempo <= 120) {
 				// FPS
 				_currentFrameRate = tempo;
-				if (g_director->_fpsLimit)
-					_currentFrameRate = MIN(g_director->_fpsLimit, _currentFrameRate);
+				if (_vm->_fpsLimit)
+					_currentFrameRate = MIN(_vm->_fpsLimit, _currentFrameRate);
 				_nextFrameTime = g_system->getMillis() + 1000.0 / (float)_currentFrameRate;
 				debugC(5, kDebugEvents, "Score::updateNextFrameTime(): setting _nextFrameTime to %d based on a framerate of %d", _nextFrameTime, _currentFrameRate);
 			} else {
@@ -600,8 +600,8 @@ void Score::updateNextFrameTime() {
 			} else if (tempo == 246) {
 				// FPS
 				_currentFrameRate = tempoCuePoint;
-				if (g_director->_fpsLimit)
-					_currentFrameRate = MIN(g_director->_fpsLimit, _currentFrameRate);
+				if (_vm->_fpsLimit)
+					_currentFrameRate = MIN(_vm->_fpsLimit, _currentFrameRate);
 				_nextFrameTime = g_system->getMillis() + 1000.0 / (float)_currentFrameRate;
 				debugC(5, kDebugEvents, "Score::updateNextFrameTime(): setting _nextFrameTime to %d based on a framerate of %d", _nextFrameTime, _currentFrameRate);
 			} else {
@@ -853,7 +853,7 @@ void Score::renderFrame(uint16 frameId, RenderMode mode, bool sound1Changed, boo
 		incrementFilmLoops();
 		_window->render();
 		_skipTransition = false;
-	} else if (g_director->_playbackPaused) {
+	} else if (_vm->_playbackPaused) {
 		updateSprites(mode);
 		incrementFilmLoops();
 		_window->render();
@@ -1012,8 +1012,8 @@ bool Score::renderPrePaletteCycle(RenderMode mode) {
 		if (debugChannelSet(-1, kDebugFast))
 			frameRate = 30;
 
-		if (g_director->_fpsLimit)
-			frameRate = MIN((int)g_director->_fpsLimit, frameRate);
+		if (_vm->_fpsLimit)
+			frameRate = MIN((int)_vm->_fpsLimit, frameRate);
 
 		int frameDelay = 1000 / 60;
 		int fadeFrames = kFadeColorFrames[frameRate - 1];
@@ -1023,8 +1023,8 @@ bool Score::renderPrePaletteCycle(RenderMode mode) {
 
 		// Copy the current palette into the snapshot buffer
 		memset(_paletteSnapshotBuffer, 0, 768);
-		memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
-		PaletteV4 *destPal = g_director->getPalette(currentPalette);
+		memcpy(_paletteSnapshotBuffer, _vm->getPalette(), _vm->getPaletteColorCount() * 3);
+		PaletteV4 *destPal = _vm->getPalette(currentPalette);
 		if (!destPal) {
 			warning("Unable to fetch palette %s", currentPalette.asString().c_str());
 			return false;
@@ -1033,7 +1033,7 @@ bool Score::renderPrePaletteCycle(RenderMode mode) {
 		if (_currentFrame->_mainChannels.palette.normal) {
 			// If the target palette ID is the same as the previous palette ID,
 			// a normal fade is a no-op.
-			if (_currentFrame->_mainChannels.palette.paletteId == g_director->_lastPalette) {
+			if (_currentFrame->_mainChannels.palette.paletteId == _vm->_lastPalette) {
 				return false;
 			}
 
@@ -1049,20 +1049,20 @@ bool Score::renderPrePaletteCycle(RenderMode mode) {
 					i + 1,
 					fadeFrames
 				);
-				g_director->setPalette(calcPal, 256);
-				g_director->draw();
+				_vm->setPalette(calcPal, 256);
+				_vm->draw();
 				if (_activeFade) {
 					_activeFade = _soundManager->fadeChannels();
 				}
 				// On click, stop loop and reset palette
-				if (_vm->processEvents(true)) {
+				if (_vm->processSysEvents(true)) {
 					debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): interrupted, setting palette to %s", currentPalette.asString().c_str());
-					g_director->setPalette(currentPalette);
+					_vm->setPalette(currentPalette);
 					return true;
 				}
 				uint32 endTime = g_system->getMillis();
 				int diff = (int)frameDelay - (int)(endTime - startTime);
-				g_director->delayMillis(MAX(0, diff));
+				_vm->delayMillis(MAX(0, diff));
 			}
 
 		} else {
@@ -1092,20 +1092,20 @@ bool Score::renderPrePaletteCycle(RenderMode mode) {
 					i + 1,
 					fadeFrames
 				);
-				g_director->setPalette(calcPal, 256);
-				g_director->draw();
+				_vm->setPalette(calcPal, 256);
+				_vm->draw();
 				if (_activeFade) {
 					_activeFade = _soundManager->fadeChannels();
 				}
 				// On click, stop loop and reset palette
-				if (_vm->processEvents(true)) {
+				if (_vm->processSysEvents(true)) {
 					debugC(2, kDebugImages, "Score::renderPrePaletteCycle(): interrupted, setting palette to %s", currentPalette.asString().c_str());
-					g_director->setPalette(currentPalette);
+					_vm->setPalette(currentPalette);
 					return true;
 				}
 				uint32 endTime = g_system->getMillis();
 				int diff = (int)frameDelay - (int)(endTime - startTime);
-				g_director->delayMillis(MAX(0, diff));
+				_vm->delayMillis(MAX(0, diff));
 			}
 		}
 	}
@@ -1120,19 +1120,19 @@ void Score::setLastPalette() {
 	CastMemberID currentPalette = _currentFrame->_mainChannels.palette.paletteId;
 	// Director allows you to use palette IDs for cast members
 	// that have long since been erased. Check all of them.
-	if (!g_director->hasPalette(currentPalette))
+	if (!_vm->hasPalette(currentPalette))
 		currentPalette = CastMemberID();
 	// Palette not specified in the frame
 	if (currentPalette.isNull()) {
 		// Use the score cached palette ID
 		isCachedPalette = true;
 		currentPalette = _currentFrame->_mainChannels.scoreCachedPaletteId;
-		if (!g_director->hasPalette(currentPalette))
+		if (!_vm->hasPalette(currentPalette))
 			currentPalette = CastMemberID();
 		// The cached ID is created before the cast gets loaded; if it's zero,
 		// this corresponds to the movie default palette.
 		if (currentPalette.isNull()) {
-			currentPalette = g_director->getCurrentMovie()->_defaultPalette;
+			currentPalette = _vm->getCurrentMovie()->_defaultPalette;
 		}
 		// If for whatever reason this doesn't resolve, abort.
 		if (currentPalette.isNull())
@@ -1141,17 +1141,17 @@ void Score::setLastPalette() {
 
 	// If the palette is defined in the frame and doesn't match
 	// the current one, set it
-	bool paletteChanged = (currentPalette != g_director->_lastPalette) && (!currentPalette.isNull());
+	bool paletteChanged = (currentPalette != _vm->_lastPalette) && (!currentPalette.isNull());
 	if (paletteChanged) {
 		debugC(2, kDebugImages, "Score::setLastPalette(): palette changed to %s, from %s", currentPalette.asString().c_str(), isCachedPalette ? "cache" :"frame");
-		g_director->_lastPalette = currentPalette;
+		_vm->_lastPalette = currentPalette;
 		_paletteTransitionIndex = 0;
 
 		// Switch to a new palette immediately if:
 		// - this is color cycling mode, or
 		// - the cached palette ID is different (i.e. we jumped in the score)
 		if (_currentFrame->_mainChannels.palette.colorCycling || isCachedPalette)
-			g_director->setPalette(g_director->_lastPalette);
+			_vm->setPalette(_vm->_lastPalette);
 	}
 
 }
@@ -1184,8 +1184,8 @@ void Score::renderPaletteCycle(RenderMode mode) {
 		return;
 
 	// Apply the global FPS limit if required
-	if (g_director->_fpsLimit)
-		speed = MIN((int)g_director->_fpsLimit, speed);
+	if (_vm->_fpsLimit)
+		speed = MIN((int)_vm->_fpsLimit, speed);
 
 	if (debugChannelSet(-1, kDebugFast))
 		speed = 30;
@@ -1200,12 +1200,12 @@ void Score::renderPaletteCycle(RenderMode mode) {
 		if (_currentFrame->_mainChannels.palette.overTime) {
 			// Do a single color step in one frame transition
 			debugC(2, kDebugImages, "Score::renderPaletteCycle(): color cycle palette %s, from colors %d to %d, by 1 frame", currentPalette.asString().c_str(), firstColor, lastColor);
-			g_director->shiftPalette(firstColor, lastColor, false);
-			g_director->draw();
+			_vm->shiftPalette(firstColor, lastColor, false);
+			_vm->draw();
 		} else {
 			// Short circuit for few frames renderer
 			if (debugChannelSet(-1, kDebugFast)) {
-				g_director->setPalette(currentPalette);
+				_vm->setPalette(currentPalette);
 				return;
 			}
 
@@ -1215,43 +1215,43 @@ void Score::renderPaletteCycle(RenderMode mode) {
 			for (int i = 0; i < _currentFrame->_mainChannels.palette.cycleCount; i++) {
 				for (int j = 0; j < steps; j++) {
 					uint32 startTime = g_system->getMillis();
-					g_director->shiftPalette(firstColor, lastColor, false);
-					g_director->draw();
+					_vm->shiftPalette(firstColor, lastColor, false);
+					_vm->draw();
 					if (_activeFade) {
 						_activeFade = _soundManager->fadeChannels();
 					}
 					// On click, stop loop and reset palette
-					if (_vm->processEvents(true)) {
-						g_director->setPalette(currentPalette);
+					if (_vm->processSysEvents(true)) {
+						_vm->setPalette(currentPalette);
 						return;
 					}
 					uint32 endTime = g_system->getMillis();
 					int diff = (int)delay - (int)(endTime - startTime);
-					g_director->delayMillis(MAX(0, diff));
+					_vm->delayMillis(MAX(0, diff));
 				}
 				if (_currentFrame->_mainChannels.palette.autoReverse) {
 					for (int j = 0; j < steps; j++) {
 						uint32 startTime = g_system->getMillis();
-						g_director->shiftPalette(firstColor, lastColor, true);
-						g_director->draw();
+						_vm->shiftPalette(firstColor, lastColor, true);
+						_vm->draw();
 						if (_activeFade) {
 							_activeFade = _soundManager->fadeChannels();
 						}
 						// On click, stop loop and reset palette
-						if (_vm->processEvents(true)) {
-							g_director->setPalette(currentPalette);
+						if (_vm->processSysEvents(true)) {
+							_vm->setPalette(currentPalette);
 							return;
 						}
 						uint32 endTime = g_system->getMillis();
 						int diff = (int)delay - (int)(endTime - startTime);
-						g_director->delayMillis(MAX(0, diff));
+						_vm->delayMillis(MAX(0, diff));
 					}
 				}
 			}
 		}
 	} else {
 		// Transition from the current palette to a new palette
-		PaletteV4 *destPal = g_director->getPalette(currentPalette);
+		PaletteV4 *destPal = _vm->getPalette(currentPalette);
 		if (!destPal) {
 			warning("Score::renderPaletteCycle(): no match for palette id %s", currentPalette.asString().c_str());
 			return;
@@ -1264,7 +1264,7 @@ void Score::renderPaletteCycle(RenderMode mode) {
 			if (_paletteTransitionIndex == 0) {
 				// Copy the current palette into the snapshot buffer
 				memset(_paletteSnapshotBuffer, 0, 768);
-				memcpy(_paletteSnapshotBuffer, g_director->getPalette(), g_director->getPaletteColorCount() * 3);
+				memcpy(_paletteSnapshotBuffer, _vm->getPalette(), _vm->getPaletteColorCount() * 3);
 				debugC(2, kDebugImages, "Score::renderPaletteCycle(): fading palette to %s over %d frames", currentPalette.asString().c_str(), frameCount);
 			}
 
@@ -1312,14 +1312,14 @@ void Score::renderPaletteCycle(RenderMode mode) {
 					);
 				}
 			}
-			g_director->setPalette(calcPal, 256);
+			_vm->setPalette(calcPal, 256);
 			_paletteTransitionIndex++;
 			_paletteTransitionIndex %= frameCount;
 		} else {
 			// Short circuit for fast renderer
 			if (debugChannelSet(-1, kDebugFast)) {
 				debugC(2, kDebugImages, "Score::renderPaletteCycle(): setting palette to %s", currentPalette.asString().c_str());
-				g_director->setPalette(currentPalette);
+				_vm->setPalette(currentPalette);
 				return;
 			}
 
@@ -1342,8 +1342,8 @@ void Score::renderPaletteCycle(RenderMode mode) {
 				if (debugChannelSet(-1, kDebugFast))
 					frameRate = 30;
 
-				if (g_director->_fpsLimit)
-					frameRate = MIN((int)g_director->_fpsLimit, frameRate);
+				if (_vm->_fpsLimit)
+					frameRate = MIN((int)_vm->_fpsLimit, frameRate);
 
 				int frameDelay = 1000 / 60;
 				int fadeFrames = kFadeColorFrames[frameRate - 1];
@@ -1351,22 +1351,22 @@ void Score::renderPaletteCycle(RenderMode mode) {
 					fadeFrames = kFadeColorFramesD5[frameRate - 1];
 
 				// Wait for a fixed time
-				g_director->setPalette(fadePal, 256);
-				g_director->draw();
+				_vm->setPalette(fadePal, 256);
+				_vm->draw();
 				for (int i = 0; i < kFadeColorWait; i++) {
 					uint32 startTime = g_system->getMillis();
 					if (_activeFade) {
 						_activeFade = _soundManager->fadeChannels();
 					}
 					// On click, stop loop and reset palette
-					if (_vm->processEvents(true)) {
+					if (_vm->processSysEvents(true)) {
 						debugC(2, kDebugImages, "Score::renderPaletteCycle(): interrupted, setting palette to %s", currentPalette.asString().c_str());
-						g_director->setPalette(currentPalette);
+						_vm->setPalette(currentPalette);
 						return;
 					}
 					uint32 endTime = g_system->getMillis();
 					int diff = (int)frameDelay - (int)(endTime - startTime);
-					g_director->delayMillis(MAX(0, diff));
+					_vm->delayMillis(MAX(0, diff));
 				}
 
 				debugC(2, kDebugImages, "Score::renderPaletteCycle(): fading palette to %s over %d frames", currentPalette.asString().c_str(), fadeFrames);
@@ -1380,20 +1380,20 @@ void Score::renderPaletteCycle(RenderMode mode) {
 						i + 1,
 						fadeFrames
 					);
-					g_director->setPalette(calcPal, 256);
-					g_director->draw();
+					_vm->setPalette(calcPal, 256);
+					_vm->draw();
 					if (_activeFade) {
 						_activeFade = _soundManager->fadeChannels();
 					}
 					// On click, stop loop and reset palette
-					if (_vm->processEvents(true)) {
+					if (_vm->processSysEvents(true)) {
 						debugC(2, kDebugImages, "Score::renderPaletteCycle(): interrupted, setting palette to %s", currentPalette.asString().c_str());
-						g_director->setPalette(currentPalette);
+						_vm->setPalette(currentPalette);
 						return;
 					}
 					uint32 endTime = g_system->getMillis();
 					int diff = (int)frameDelay - (int)(endTime - startTime);
-					g_director->delayMillis(MAX(0, diff));
+					_vm->delayMillis(MAX(0, diff));
 				}
 
 			}
@@ -1435,8 +1435,8 @@ void Score::renderCursor(Common::Point pos, bool forceUpdate) {
 
 			// try to use the cursor read from exe file.
 			// currently, we are using mac arrow to represent custom win cursor since we didn't find where it stores. So i comment it out here.
-//			if (g_director->getPlatform() == Common::kPlatformWindows && _channels[spriteId]->_cursor._cursorType == Graphics::kMacCursorCustom)
-//				_vm->_wm->replaceCursor(_channels[spriteId]->_cursor._cursorType, g_director->_winCursor[_channels[spriteId]->_cursor._cursorResId]);
+//			if (_vm->getPlatform() == Common::kPlatformWindows && _channels[spriteId]->_cursor._cursorType == Graphics::kMacCursorCustom)
+//				_vm->_wm->replaceCursor(_channels[spriteId]->_cursor._cursorType, _vm->_winCursor[_channels[spriteId]->_cursor._cursorResId]);
 			_vm->_wm->replaceCursor(_channels[spriteId]->_cursor._cursorType, &_channels[spriteId]->_cursor);
 			_currentCursor = _channels[spriteId]->_cursor.getRef();
 			return;
@@ -1531,9 +1531,9 @@ void Score::screenShot() {
 	Graphics::Surface *newSurface = rawSurface.convertTo(requiredFormat_4byte, _vm->getPalette());
 
 	Common::String currentPath = _vm->getCurrentPath().c_str();
-	Common::replace(currentPath, Common::String(g_director->_dirSeparator), "-"); // exclude dir separator from screenshot filename prefix
+	Common::replace(currentPath, Common::String(_vm->_dirSeparator), "-"); // exclude dir separator from screenshot filename prefix
 	Common::String prefix = Common::String::format("%s%s", currentPath.c_str(), Common::punycode_encodefilename(_movie->getMacName()).c_str());
-	Common::Path filename = dumpScriptName(prefix.c_str(), kMovieScript, g_director->_framesRan, "png");
+	Common::Path filename = dumpScriptName(prefix.c_str(), kMovieScript, _vm->_framesRan, "png");
 
 	const char *buildNumber = getenv("BUILD_NUMBER");
 
@@ -1543,7 +1543,7 @@ void Score::screenShot() {
 		// ./dumps/theapartment/25/xn--Main Menu-zd0e-19.png
 
 		Common::Path buildDir(Common::String::format("%s/%s", ConfMan.get("screenshotpath").c_str(),
-			g_director->getTargetName().c_str()), '/');
+			_vm->getTargetName().c_str()), '/');
 
 		// We run for the first time, let's check if we had the directory previously
 		if (_previousBuildBotBuild == -1) {
@@ -1559,7 +1559,7 @@ void Score::screenShot() {
 
 		// Now we try to find any previous dump
 		while (prevbuild > 0) {
-			filename = buildDir.join(Common::Path(Common::String::format("%d/%s-%d.png", prevbuild, prefix.c_str(), g_director->_framesRan), '/'));
+			filename = buildDir.join(Common::Path(Common::String::format("%d/%s-%d.png", prevbuild, prefix.c_str(), _vm->_framesRan), '/'));
 
 			Common::FSNode fs(filename);
 
@@ -1594,7 +1594,7 @@ void Score::screenShot() {
 		// the screenshot was different from the previous one.
 		//
 		// Regenerate file name with the correct build number
-		filename = buildDir.join(Common::Path(Common::String::format("%s/%s-%d.png", buildNumber, prefix.c_str(), g_director->_framesRan), '/'));
+		filename = buildDir.join(Common::Path(Common::String::format("%s/%s-%d.png", buildNumber, prefix.c_str(), _vm->_framesRan), '/'));
 	}
 
 	Common::DumpFile screenshotFile;
@@ -1613,7 +1613,7 @@ void Score::screenShot() {
 }
 
 uint16 Score::getSpriteIDOfActiveWidget() {
-	Graphics::MacWidget *active = g_director->_wm->getActiveWidget();
+	Graphics::MacWidget *active = _vm->_wm->getActiveWidget();
 	if (!active)
 		return 0;
 	for (int i = _channels.size() - 1; i >= 0; i--) {
@@ -2404,16 +2404,16 @@ void Score::loadActions(Common::SeekableReadStreamEndian &stream) {
 Common::String Score::formatChannelInfo() {
 	Frame &frame = *_currentFrame;
 	Common::String result;
-	CastMemberID defaultPalette = g_director->getCurrentMovie()->_defaultPalette;
+	CastMemberID defaultPalette = _vm->getCurrentMovie()->_defaultPalette;
 	result += Common::String::format("TMPO:   tempo: %d, skipFrameFlag: %d, blend: %d, currentFPS: %d\n",
 		frame._mainChannels.tempo, frame._mainChannels.skipFrameFlag, frame._mainChannels.blend, _currentFrameRate);
 	if (!frame._mainChannels.palette.paletteId.isNull()) {
 		result += Common::String::format("PAL:    paletteId: %s, firstColor: %d, lastColor: %d, flags: %d, cycleCount: %d, speed: %d, frameCount: %d, fade: %d, delay: %d, style: %d, currentId: %s, defaultId: %s\n",
 			frame._mainChannels.palette.paletteId.asString().c_str(), frame._mainChannels.palette.firstColor, frame._mainChannels.palette.lastColor, frame._mainChannels.palette.flags,
 			frame._mainChannels.palette.cycleCount, frame._mainChannels.palette.speed, frame._mainChannels.palette.frameCount,
-			frame._mainChannels.palette.fade, frame._mainChannels.palette.delay, frame._mainChannels.palette.style, g_director->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
+			frame._mainChannels.palette.fade, frame._mainChannels.palette.delay, frame._mainChannels.palette.style, _vm->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
 	} else {
-		result += Common::String::format("PAL:    paletteId: 000, currentId: %s, defaultId: %s\n", g_director->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
+		result += Common::String::format("PAL:    paletteId: 000, currentId: %s, defaultId: %s\n", _vm->_lastPalette.asString().c_str(), defaultPalette.asString().c_str());
 	}
 	result += Common::String::format("TRAN:   transType: %d, transDuration: %d, transChunkSize: %d\n",
 		frame._mainChannels.transType, frame._mainChannels.transDuration, frame._mainChannels.transChunkSize);
diff --git a/engines/director/transitions.cpp b/engines/director/transitions.cpp
index 46894c6a869..c7955b75e19 100644
--- a/engines/director/transitions.cpp
+++ b/engines/director/transitions.cpp
@@ -566,7 +566,7 @@ void Window::playTransition(uint frame, RenderMode mode, uint16 transDuration, u
 
 		composeSurface->blitFrom(*blitFrom, rfrom, Common::Point(rto.left, rto.top));
 
-		if (_vm->processEvents(true)) {
+		if (_vm->processSysEvents(true)) {
 			exitTransition(t, &nextFrame, clipRect);
 			break;
 		}
@@ -781,7 +781,7 @@ void Window::dissolveTrans(TransParams &t, Common::Rect &clipRect, Graphics::Man
 
 		g_lingo->executePerFrameHook(t.frame, i + 1, false);
 
-		if (_vm->processEvents(true)) {
+		if (_vm->processSysEvents(true)) {
 			exitTransition(t, nextFrame, clipRect);
 			break;
 		}
@@ -907,7 +907,7 @@ void Window::dissolvePatternsTrans(TransParams &t, Common::Rect &clipRect, Graph
 
 		g_lingo->executePerFrameHook(t.frame, i + 1, false);
 
-		if (_vm->processEvents(true)) {
+		if (_vm->processSysEvents(true)) {
 			exitTransition(t, nextFrame, clipRect);
 			break;
 		}
@@ -1092,7 +1092,7 @@ void Window::transMultiPass(TransParams &t, Common::Rect &clipRect, Graphics::Ma
 		debugC(6, kDebugImages, "Window::transMultiPass(): delaying for %d", diff);
 		g_director->delayMillis(diff);
 
-		if (_vm->processEvents(true)) {
+		if (_vm->processSysEvents(true)) {
 			exitTransition(t, nextFrame, clipRect);
 			break;
 		}
@@ -1146,7 +1146,7 @@ void Window::transZoom(TransParams &t, Common::Rect &clipRect, Graphics::Managed
 		r.setWidth(t.xStepSize * i * 2 / TSTEP_FRAC);
 		r.moveTo(clipRect.left + w / 2 - t.xStepSize * i / TSTEP_FRAC, clipRect.top + h / 2 - t.yStepSize * i / TSTEP_FRAC);
 
-		if (_vm->processEvents(true)) {
+		if (_vm->processSysEvents(true)) {
 			exitTransition(t, nextFrame, clipRect);
 			break;
 		}
diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 9602f3e4e6f..6f9d18be1c8 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -617,7 +617,7 @@ bool Window::loadNextMovie() {
 			while (delay != 0) {
 				uint32 dec = MIN((uint32)10, delay);
 				// Skip delay if mouse is clicked
-				if (g_director->processEvents(true, true)) {
+				if (g_director->processSysEvents(true, true)) {
 					g_director->loadSlowdownCooloff();
 					break;
 				}
diff --git a/engines/director/window.h b/engines/director/window.h
index 5c0bc63a505..0139e0cb962 100644
--- a/engines/director/window.h
+++ b/engines/director/window.h
@@ -187,7 +187,7 @@ public:
 	static void inkBlitFrom(Channel *channel, Common::Rect destRect, Graphics::ManagedSurface *blitTo = nullptr);
 
 	// events.cpp
-	bool processEvent(Common::Event &event);
+	bool processSysEvent(Common::Event &event);
 	bool processWMEvent(Graphics::WindowClick click, Common::Event &event);
 	void sendWindowEvent(LEvent event);
 
diff --git a/graphics/macgui/macwindow.cpp b/graphics/macgui/macwindow.cpp
index 4199132057c..2823c889644 100644
--- a/graphics/macgui/macwindow.cpp
+++ b/graphics/macgui/macwindow.cpp
@@ -618,7 +618,7 @@ bool MacWindow::processEvent(Common::Event &event) {
 			return result;
 
 		if (_wm->getActiveWidget())
-			return _wm->getActiveWidget()->processEvent(event) || result;
+			return result && _wm->getActiveWidget()->processEvent(event);
 
 		return result;
 


Commit: ff813b5efcca39de6b1d01c390f6a166eb2abd61
    https://github.com/scummvm/scummvm/commit/ff813b5efcca39de6b1d01c390f6a166eb2abd61
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Clear window modal flag in destructor

Fixes option screen freeze after saving in Opera Fatal.

Changed paths:
    engines/director/window.cpp


diff --git a/engines/director/window.cpp b/engines/director/window.cpp
index 6f9d18be1c8..295d262fb48 100644
--- a/engines/director/window.cpp
+++ b/engines/director/window.cpp
@@ -91,6 +91,10 @@ Window::~Window() {
 		delete _frozenLingoStates[i];
 	if (_puppetTransition)
 		delete _puppetTransition;
+	if (_isModal) {
+		_wm->setLockedWidget(nullptr);
+		_isModal = false;
+	}
 	g_director->_wm->removeWindow(_window);
 	g_director->_wm->removeMarked();
 	_window = nullptr;


Commit: bbc58f2b47eaca226b43cf7932429fe2fb603833
    https://github.com/scummvm/scummvm/commit/bbc58f2b47eaca226b43cf7932429fe2fb603833
Author: Scott Percival (code at moral.net.au)
Date: 2026-06-01T20:06:27+02:00

Commit Message:
DIRECTOR: Comment out crash-inducing movie export debug code

Changed paths:
    engines/director/cast.cpp
    engines/director/castmember/filmloop.cpp
    engines/director/castmember/palette.cpp
    engines/director/castmember/text.cpp


diff --git a/engines/director/cast.cpp b/engines/director/cast.cpp
index ef9b52d450d..1915d5d1558 100644
--- a/engines/director/cast.cpp
+++ b/engines/director/cast.cpp
@@ -694,7 +694,8 @@ void Cast::saveConfig(Common::SeekableWriteStream *writeStream, uint32 offset) {
 		writeStream->writeSint16BE(_windowDragRegionMaskId.member);
 	}
 
-	if (debugChannelSet(7, kDebugSaving)) {
+	// FIXME: can't dereference SeekableWriteStream
+	/*if (debugChannelSet(7, kDebugSaving)) {
 		// Adding +8 because the stream doesn't include the header and the entry for the size itself
 		byte *dumpData = (byte *)calloc(configSize + 8, sizeof(byte));
 
@@ -708,7 +709,7 @@ void Cast::saveConfig(Common::SeekableWriteStream *writeStream, uint32 offset) {
 		dumpFile("ConfigData", 0, MKTAG('V', 'W', 'C', 'F'), dumpData, configSize + 8);
 		free(dumpData);
 		delete dumpStream;
-	}
+	}*/
 
 }
 
@@ -950,7 +951,8 @@ void Cast::saveCastData(Common::SeekableWriteStream *writeStream, Resource *res)
 
 	debugC(5, kDebugSaving, "Cast::saveCastData()::Saving 'CASt' resource, id: %d, size: %d, type: %s", id, castSize, castType2str(type));
 
-	if (debugChannelSet(7, kDebugSaving)) {
+	// FIXME: can't dereference SeekableWriteStream
+	/*if (debugChannelSet(7, kDebugSaving)) {
 		byte *dumpData = (byte *)calloc(castSize + 8, sizeof(byte));
 		Common::SeekableMemoryWriteStream *dumpStream = new Common::SeekableMemoryWriteStream(dumpData, castSize + 8);
 
@@ -962,7 +964,7 @@ void Cast::saveCastData(Common::SeekableWriteStream *writeStream, Resource *res)
 		dumpFile(castType2str(type), res->index, MKTAG('C', 'A', 'S', 't'), dumpData, castSize + 8);
 		free(dumpData);
 		delete dumpStream;
-	}
+	}*/
 }
 
 void Cast::writeCastInfo(Common::SeekableWriteStream *writeStream, uint32 castId) {
diff --git a/engines/director/castmember/filmloop.cpp b/engines/director/castmember/filmloop.cpp
index 1ca1764d6c3..ca01dfd5440 100644
--- a/engines/director/castmember/filmloop.cpp
+++ b/engines/director/castmember/filmloop.cpp
@@ -360,7 +360,8 @@ void FilmLoopCastMember::writeSCVWResource(Common::SeekableWriteStream *writeStr
 
 	}
 
-	if (debugChannelSet(7, kDebugSaving)) {
+	// FIXME: can't dereference SeekableWriteStream
+	/*if (debugChannelSet(7, kDebugSaving)) {
 		// Adding +8 because the stream doesn't include the header and the entry for the size itself
 		byte *dumpData = (byte *)calloc(filmloopSize + 8, sizeof(byte));
 
@@ -374,7 +375,7 @@ void FilmLoopCastMember::writeSCVWResource(Common::SeekableWriteStream *writeStr
 		dumpFile("FilmLoopData", 0, MKTAG('V', 'W', 'C', 'F'), dumpData, filmloopSize);
 		free(dumpData);
 		delete dumpStream;
-	}
+	}*/
 }
 
 uint32 FilmLoopCastMember::getSCVWResourceSize() {
diff --git a/engines/director/castmember/palette.cpp b/engines/director/castmember/palette.cpp
index 0a59f067cd5..6994cff3edb 100644
--- a/engines/director/castmember/palette.cpp
+++ b/engines/director/castmember/palette.cpp
@@ -183,7 +183,8 @@ void PaletteCastMember::writePaletteData(Common::SeekableWriteStream *writeStrea
 		writeStream->writeUint16BE(pal[3 * i + 2] << 8);
 	}
 
-	if (debugChannelSet(7, kDebugSaving)) {
+	// FIXME: can't dereference SeekableWriteStream
+	/* if (debugChannelSet(7, kDebugSaving)) {
 		byte *dumpData = nullptr;
 		dumpData = (byte *)calloc(castSize, sizeof(byte));
 		auto dumpStream = new Common::SeekableMemoryWriteStream(dumpData, castSize + 8);
@@ -196,7 +197,7 @@ void PaletteCastMember::writePaletteData(Common::SeekableWriteStream *writeStrea
 		dumpFile("PaletteData", _castId, MKTAG('C', 'L', 'U', 'T'), dumpData, castSize);
 		free(dumpData);
 		delete dumpStream;
-	}
+	}*/
 }
 
 }	// End of namespace Director
diff --git a/engines/director/castmember/text.cpp b/engines/director/castmember/text.cpp
index 06806dd8ecf..7fd5a312104 100644
--- a/engines/director/castmember/text.cpp
+++ b/engines/director/castmember/text.cpp
@@ -1085,7 +1085,8 @@ uint32 TextCastMember::writeSTXTResource(Common::SeekableWriteStream *writeStrea
 	writeStream->writeString(rawText);
 	writeStream->seek(currentPos);
 
-	if (debugChannelSet(7, kDebugSaving)) {
+	// FIXME: can't dereference SeekableWriteStream
+	/*if (debugChannelSet(7, kDebugSaving)) {
 		byte *dumpData = nullptr;
 		dumpData = (byte *)calloc(stxtSize, sizeof(byte));
 		Common::MemoryWriteStream *dumpStream = new Common::SeekableMemoryWriteStream(dumpData, stxtSize);
@@ -1098,7 +1099,7 @@ uint32 TextCastMember::writeSTXTResource(Common::SeekableWriteStream *writeStrea
 		dumpFile("TextData", _castId, MKTAG('S', 'T', 'X', 'T'), dumpData, getSTXTResourceSize() + 8);
 		free(dumpData);
 		delete dumpStream;
-	}
+	}*/
 
 	return stxtSize + 8;
 }




More information about the Scummvm-git-logs mailing list