51 using std::make_shared;
59 virtual string execute(
const vector<string>& tokens);
60 virtual string help(
const vector<string>& tokens)
const;
69 virtual string execute(
const vector<string>& tokens);
70 virtual string help(
const vector<string>& tokens)
const;
80 virtual string execute(
const vector<string>& tokens);
81 virtual string help(
const vector<string>& tokens)
const;
91 virtual string execute(
const vector<string>& tokens);
92 virtual string help(
const vector<string>& tokens)
const;
101 virtual string execute(
const vector<string>& tokens);
102 virtual string help(
const vector<string>& tokens)
const;
112 virtual void execute(
const vector<TclObject>& tokens,
114 virtual string help(
const vector<string>& tokens)
const;
123 virtual string execute(
const vector<string>& tokens);
124 virtual string help(
const vector<string>& tokens)
const;
134 virtual string execute(
const vector<string>& tokens);
135 virtual string help(
const vector<string>& tokens)
const;
145 virtual string execute(
const vector<string>& tokens);
146 virtual string help(
const vector<string>& tokens)
const;
159 virtual bool alarm();
167 virtual void execute(
const vector<TclObject>& tokens,
169 virtual string help(
const vector<string>& tokens)
const;
172 const string configName;
179 virtual void execute(
const vector<TclObject>& tokens,
181 virtual string help(
const vector<string>& tokens)
const;
183 const uint64_t reference;
189 , activeBoard(nullptr)
199 eventDistributor = make_unique<EventDistributor>(*this);
200 globalCliComm = make_unique<GlobalCliComm>();
201 globalCommandController = make_unique<GlobalCommandController>(
202 *eventDistributor, *globalCliComm, *
this);
203 globalSettings = make_unique<GlobalSettings>(
204 *globalCommandController);
205 inputEventGenerator = make_unique<InputEventGenerator>(
206 *globalCommandController, *eventDistributor);
207 mixer = make_unique<Mixer>(
208 *
this, *globalCommandController);
209 diskFactory = make_unique<DiskFactory>(
211 diskManipulator = make_unique<DiskManipulator>(
212 *globalCommandController, *
this);
213 virtualDrive = make_unique<DiskChanger>(
214 "virtual_drive", *globalCommandController,
215 *diskFactory, *diskManipulator,
true);
216 filePool = make_unique<FilePool>(
217 *globalCommandController, *eventDistributor);
218 userSettings = make_unique<UserSettings>(
219 *globalCommandController);
220 softwareDatabase = make_unique<RomDatabase>(
221 *globalCommandController, *globalCliComm);
222 afterCommand = make_unique<AfterCommand>(
223 *
this, *eventDistributor, *globalCommandController);
224 quitCommand = make_unique<QuitCommand>(
225 *globalCommandController, *eventDistributor);
226 messageCommand = make_unique<MessageCommand>(
227 *globalCommandController);
228 machineCommand = make_unique<MachineCommand>(
229 *globalCommandController, *
this);
230 testMachineCommand = make_unique<TestMachineCommand>(
231 *globalCommandController, *
this);
232 createMachineCommand = make_unique<CreateMachineCommand>(
233 *globalCommandController, *
this);
234 deleteMachineCommand = make_unique<DeleteMachineCommand>(
235 *globalCommandController, *
this);
236 listMachinesCommand = make_unique<ListMachinesCommand>(
237 *globalCommandController, *
this);
238 activateMachineCommand = make_unique<ActivateMachineCommand>(
239 *globalCommandController, *
this);
240 storeMachineCommand = make_unique<StoreMachineCommand>(
241 *globalCommandController, *
this);
242 restoreMachineCommand = make_unique<RestoreMachineCommand>(
243 *globalCommandController, *
this);
244 aviRecordCommand = make_unique<AviRecorder>(*this);
245 extensionInfo = make_unique<ConfigInfo>(
247 machineInfo = make_unique<ConfigInfo>(
249 realTimeInfo = make_unique<RealTimeInfo>(
251 tclCallbackMessages = make_unique<TclCallbackMessages>(
252 *globalCliComm, *globalCommandController);
254 createMachineSetting();
267 deleteBoard(activeBoard);
278 return *eventDistributor;
283 return *globalCommandController;
288 return *globalCliComm;
293 return *globalCliComm;
298 return *inputEventGenerator;
303 assert(display.get());
309 return *softwareDatabase;
329 return *diskManipulator;
334 return *machineSetting;
339 return *globalSettings;
344 return *globalCommandController;
349 return globalCommandController->getOpenMSXInfoCommand();
354 vector<string> result;
358 while (
auto* entry = configsDir.
getEntry()) {
364 result.push_back(name.
str());
367 fullname,
"hardwareconfig.xml");
369 result.push_back(name.
str());
375 sort(result.begin(), result.end());
376 result.erase(unique(result.begin(), result.end()), result.end());
380 void Reactor::createMachineSetting()
385 machines[name] = count++;
387 machines[
"C-BIOS_MSX2+"] = 0;
389 machineSetting = make_unique<EnumSetting<int>>(
390 *globalCommandController,
"default_machine",
391 "default machine (takes effect next time openMSX is started)",
406 vector<string_ref> Reactor::getMachineIDs()
const
408 vector<string_ref> result;
409 for (
auto& b : boards) {
410 result.push_back(b->getMachineID());
415 MSXMotherBoard& Reactor::getMachine(
const string& machineID)
const
417 for (
auto& b : boards) {
418 if (b->getMachineID() == machineID) {
422 throw CommandException(
"No machine with ID: " + machineID);
427 return make_unique<MSXMotherBoard>(*this);
435 auto* newBoard = newBoard_.get();
436 boards.push_back(move(newBoard_));
439 auto it = boards.begin();
440 while (it->get() != &oldBoard_) {
442 assert(it != boards.end());
446 if (it->get() == activeBoard) {
447 switchBoard(newBoard);
459 if (!display.get()) {
460 display = make_unique<Display>(*this);
464 display->createVideoSystem();
475 auto* newBoard = newBoard_.get();
476 newBoard->loadMachine(machine);
477 boards.push_back(move(newBoard_));
479 auto* oldBoard = activeBoard;
480 switchBoard(newBoard);
481 deleteBoard(oldBoard);
488 (find_if(boards.begin(), boards.end(),
489 [&](Boards::value_type& b) {
return b.get() == newBoard; })
491 assert(!activeBoard ||
492 (find_if(boards.begin(), boards.end(),
493 [&](Boards::value_type& b) {
return b.get() == activeBoard; })
502 ScopedLock lock(mbSem);
503 activeBoard = newBoard;
505 eventDistributor->distributeEvent(
513 void Reactor::deleteBoard(MSXMotherBoard* board)
523 if (board == activeBoard) {
525 switchBoard(
nullptr);
527 auto it = find_if(boards.begin(), boards.end(),
528 [&](Boards::value_type& b) {
return b.get() == board; });
529 assert(it != boards.end());
530 auto board_ = move(*it);
536 garbageBoards.push_back(move(board_));
537 eventDistributor->distributeEvent(
559 pollEventGenerator->pollNow();
564 auto& commandController = *globalCommandController;
568 commandController.source(
579 throw FatalError(
"Couldn't execute script: " +
597 pollEventGenerator = make_unique<PollEventGenerator>(*eventDistributor);
600 eventDistributor->deliverEvents();
601 assert(garbageBoards.empty());
602 bool blocked = (blockedCounter > 0) || !activeBoard;
603 if (!blocked) blocked = !activeBoard->
execute();
611 eventDistributor->sleep(100 * 1000);
616 void Reactor::unpause()
625 void Reactor::pause()
644 assert(blockedCounter >= 0);
650 void Reactor::update(
const Setting& setting)
653 if (&setting == &pauseSetting) {
654 if (pauseSetting.getValue()) {
663 int Reactor::signalEvent(
const std::shared_ptr<const Event>& event)
665 auto type =
event->getType();
680 auto& focusEvent = checked_cast<
const FocusEvent&>(*event);
681 if (focusEvent.getGain()) {
690 auto& focusEvent = checked_cast<
const FocusEvent&>(*event);
691 if (focusEvent.getGain()) {
702 assert(!garbageBoards.empty());
703 garbageBoards.erase(garbageBoards.begin());
715 :
Command(commandController,
"exit")
716 , distributor(distributor_)
728 return "Use this command to stop the emulator\n";
736 :
Command(commandController,
"machine")
743 switch (tokens.size()) {
761 return "Switch to a different MSX machine.";
774 :
Command(commandController,
"test_machine")
781 if (tokens.size() != 2) {
795 return "Test the configuration for the given machine. "
796 "Returns an error message explaining why the configuration is "
797 "invalid or an empty string in case of success.";
810 :
Command(commandController,
"create_machine")
817 if (tokens.size() != 1) {
822 reactor.boards.push_back(move(newBoard));
828 return "Creates a new (empty) MSX machine. Returns the ID for the new "
830 "Use 'load_machine' to actually load a machine configuration "
831 "into this new machine.\n"
832 "The main reason create_machine and load_machine are two "
833 "separate commands is that sometimes you already want to know "
834 "the ID of the machine before load_machine starts emitting "
835 "events for this machine.";
843 :
Command(commandController,
"delete_machine")
850 if (tokens.size() != 2) {
853 reactor.deleteBoard(&reactor.getMachine(tokens[1]));
859 return "Deletes the given MSX machine.";
872 :
Command(commandController,
"list_machines")
885 return "Returns a list of all machine IDs.";
893 :
Command(commandController,
"activate_machine")
900 switch (tokens.size()) {
904 reactor.switchBoard(&reactor.getMachine(tokens[1]));
914 return "Make another machine the active msx machine.\n"
915 "Or when invoked without arguments, query the ID of the "
916 "active msx machine.";
929 :
Command(commandController,
"store_machine")
938 switch (tokens.size()) {
944 machineID = tokens[1];
948 machineID = tokens[1];
949 filename = tokens[2];
955 auto& board = reactor.getMachine(machineID);
965 "store_machine Save state of current machine to file \"openmsxNNNN.xml.gz\"\n"
966 "store_machine machineID Save state of machine \"machineID\" to file \"openmsxNNNN.xml.gz\"\n"
967 "store_machine machineID <filename> Save state of machine \"machineID\" to indicated file\n"
969 "This is a low-level command, the 'savestate' script is easier to use.";
982 :
Command(commandController,
"restore_machine")
993 switch (tokens.size()) {
998 string lastEntry =
"";
1001 while (dirent* d = dir.
getEntry()) {
1002 int res = stat((dirName +
string(d->d_name)).c_str(), &st);
1003 if ((res == 0) && S_ISREG(st.st_mode)) {
1004 time_t modTime = st.st_mtime;
1005 if (modTime > lastTime) {
1006 lastEntry = string(d->d_name);
1011 if (lastEntry ==
"") {
1014 filename = dirName + lastEntry;
1018 filename = tokens[1];
1040 reactor.boards.push_back(move(newBoard));
1047 "restore_machine Load state from last saved state in default directory\n"
1048 "restore_machine <filename> Load state from indicated file\n"
1050 "This is a low-level command, the 'loadstate' script is easier to use.";
1063 : eventDistributor(eventDistributor_)
1075 PollEventGenerator::alarm();
1082 bool PollEventGenerator::alarm()
1093 const string& configName_)
1094 :
InfoTopic(openMSXInfoCommand, configName_)
1095 , configName(configName_)
1103 switch (tokens.size()) {
1111 configName, tokens[2].getString());
1112 if (
auto* info = config.findChild(
"info")) {
1113 for (
auto& i : info->getChildren()) {
1120 "Couldn't get config info: " + e.
getMessage());
1131 return "Shows a list of available " + configName +
", "
1132 "or get meta information about the selected item.\n";
1144 :
InfoTopic(openMSXInfoCommand,
"realtime")
1145 , reference(Timer::getTime())
1158 return "Returns the time in seconds since openMSX was started.";