mirror of
https://github.com/cmosher01/Epple-II.git
synced 2024-09-27 07:54:58 +00:00
call sdl and wx from main thread
This commit is contained in:
parent
3d4637a939
commit
fc7806d3c9
149
src/E2wxApp.cpp
149
src/E2wxApp.cpp
@ -39,7 +39,6 @@
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <wx/debugrpt.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <algorithm>
|
||||
@ -53,13 +52,37 @@ wxIMPLEMENT_APP_NO_MAIN(E2wxApp);
|
||||
#ifndef PROJECT_VERSION
|
||||
#define PROJECT_VERSION 0.0.1
|
||||
#endif
|
||||
|
||||
|
||||
std::promise<void> E2wxApp::barrier_to_init;
|
||||
#ifndef PROJECT_VENDOR
|
||||
#define PROJECT_VENDOR nu.mine.mosher
|
||||
#endif
|
||||
#ifndef PROJECT_NAME
|
||||
#define PROJECT_NAME Epple-II
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
E2wxApp::E2wxApp() : id("nu.mine.mosher.epple2"), version(wxSTRINGIZE_T(PROJECT_VERSION)) {
|
||||
|
||||
|
||||
EmuTimer::EmuTimer(Emulator *e) : wxTimer(), emu(e) {
|
||||
}
|
||||
|
||||
EmuTimer::~EmuTimer() {
|
||||
}
|
||||
|
||||
void EmuTimer::begin() {
|
||||
this->Start(50); // TODO: EXPECTED_MS from Emulator
|
||||
}
|
||||
|
||||
void EmuTimer::Notify() {
|
||||
this->emu->tick50ms();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
E2wxApp::E2wxApp() :
|
||||
id(wxSTRINGIZE_T(PROJECT_VENDOR) wxT(".") wxSTRINGIZE_T(PROJECT_NAME)),
|
||||
version(wxSTRINGIZE_T(PROJECT_VERSION)) {
|
||||
}
|
||||
|
||||
E2wxApp::~E2wxApp() {
|
||||
@ -69,11 +92,6 @@ E2wxApp::~E2wxApp() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static std::filesystem::path dirCache() {
|
||||
return std::filesystem::path(wxStandardPaths::Get().GetUserDir(wxStandardPaths::Dir_Cache).t_str());
|
||||
}
|
||||
@ -107,6 +125,8 @@ bool E2wxApp::OnInit() {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
wxStandardPaths& stdpaths = wxStandardPaths::Get();
|
||||
//stdpaths.SetInstallPrefix(".");
|
||||
stdpaths.SetFileLayout(wxStandardPaths::FileLayout_XDG);
|
||||
@ -117,16 +137,15 @@ bool E2wxApp::OnInit() {
|
||||
|
||||
|
||||
|
||||
|
||||
this->confdir = dirConfig() / std::filesystem::path(GetID()+".d");
|
||||
this->confdir = dirConfig() / std::filesystem::path((GetID()+wxT(".d")).t_str());
|
||||
std::filesystem::create_directories(this->confdir);
|
||||
BOOST_LOG_TRIVIAL(info) << "Configuration directory path: " << this->confdir;
|
||||
|
||||
this->conffile = dirConfig() / std::filesystem::path(GetID());
|
||||
this->conffile = dirConfig() / std::filesystem::path(GetID().t_str());
|
||||
BOOST_LOG_TRIVIAL(info) << "Configuration file path: " << this->conffile;
|
||||
wxConfigBase::Set(new wxFileConfig("", "", GetID()));
|
||||
|
||||
this->docsdir = dirDocuments() / std::filesystem::path(GetID());
|
||||
this->docsdir = dirDocuments() / std::filesystem::path(GetID().t_str());
|
||||
BOOST_LOG_TRIVIAL(info) << "User document directory path: " << this->docsdir;
|
||||
|
||||
const std::filesystem::path exe = std::filesystem::path(stdpaths.GetExecutablePath().t_str());
|
||||
@ -156,38 +175,33 @@ bool E2wxApp::OnInit() {
|
||||
frame->Show();
|
||||
|
||||
|
||||
barrier_to_init.set_value();
|
||||
|
||||
this->emu = new Emulator();
|
||||
Config cfg((const std::string)this->arg_configfile.c_str());
|
||||
this->emu->config(cfg);
|
||||
this->emu->init();
|
||||
this->emu_timer = new EmuTimer(this->emu);
|
||||
this->emu_timer->begin();
|
||||
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int run(const std::string config_file) {
|
||||
GUI gui;
|
||||
|
||||
std::unique_ptr<Emulator> emu(new Emulator());
|
||||
|
||||
Config cfg(config_file);
|
||||
emu->config(cfg);
|
||||
|
||||
emu->init();
|
||||
|
||||
return emu->run();
|
||||
}
|
||||
|
||||
//void E2wxApp::StartSdlEpple2() {
|
||||
// std::cout << "starting sdl thread..." << std::endl;
|
||||
// this->thread_sdl = new std::thread(run, this->arg_configfile);
|
||||
// std::cout << "started sdl thread." << std::endl;
|
||||
//}
|
||||
|
||||
int E2wxApp::OnExit() {
|
||||
// std::cout << "stopping sdl thread..." << std::endl;
|
||||
GUI::queueQuit();
|
||||
// this->thread_sdl->join();
|
||||
// std::cout << "exiting wx application..." << std::endl;
|
||||
if (this->emu_timer) {
|
||||
delete this->emu_timer;
|
||||
}
|
||||
if (this->emu) {
|
||||
delete this->emu;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void E2wxApp::OnFatalException() {
|
||||
wxDebugReport report;
|
||||
report.AddAll();
|
||||
@ -198,33 +212,36 @@ void E2wxApp::OnFatalException() {
|
||||
}
|
||||
}
|
||||
|
||||
//static const wxCmdLineEntryDesc cmdLineDesc[] =
|
||||
//{
|
||||
// { wxCMD_LINE_PARAM, NULL, NULL, "config file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||
// wxCMD_LINE_DESC_END
|
||||
//};
|
||||
//
|
||||
//void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) {
|
||||
// wxApp::OnInitCmdLine(parser);
|
||||
// parser.SetDesc(cmdLineDesc);
|
||||
//}
|
||||
//
|
||||
//bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) {
|
||||
// if (!wxApp::OnCmdLineParsed(parser)) {
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// const int n = parser.GetParamCount();
|
||||
//
|
||||
// if (n <= 0) {
|
||||
// std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl;
|
||||
// } else {
|
||||
// this->arg_configfile = parser.GetParam(0);
|
||||
// std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl;
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
//}
|
||||
|
||||
|
||||
static const wxCmdLineEntryDesc cmdLineDesc[] =
|
||||
{
|
||||
{ wxCMD_LINE_PARAM, NULL, NULL, "config-file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||
wxCMD_LINE_DESC_END
|
||||
};
|
||||
|
||||
void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) {
|
||||
wxApp::OnInitCmdLine(parser);
|
||||
parser.SetDesc(cmdLineDesc);
|
||||
}
|
||||
|
||||
bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) {
|
||||
if (!wxApp::OnCmdLineParsed(parser)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const int n = parser.GetParamCount();
|
||||
|
||||
if (n <= 0) {
|
||||
std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl;
|
||||
} else {
|
||||
this->arg_configfile = parser.GetParam(0);
|
||||
std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const std::filesystem::path E2wxApp::GetLogFile() const {
|
||||
@ -235,7 +252,7 @@ const std::filesystem::path E2wxApp::GetResDir() const {
|
||||
return this->resdir;
|
||||
}
|
||||
|
||||
const std::string E2wxApp::GetID() const {
|
||||
const wxString E2wxApp::GetID() const {
|
||||
return this->id;
|
||||
}
|
||||
|
||||
@ -260,8 +277,8 @@ const std::filesystem::path E2wxApp::GetDocumentsDir() const {
|
||||
const std::filesystem::path E2wxApp::BuildLogFilePath() const {
|
||||
std::filesystem::path logfile =
|
||||
dirCache() /
|
||||
std::filesystem::path(GetID()) /
|
||||
std::filesystem::path("log");
|
||||
std::filesystem::path(GetID().t_str()) /
|
||||
std::filesystem::path(wxT("log"));
|
||||
|
||||
std::filesystem::create_directories(logfile);
|
||||
logfile = std::filesystem::canonical(logfile);
|
||||
|
@ -21,33 +21,55 @@
|
||||
#ifndef E2WXAPP_H
|
||||
#define E2WXAPP_H
|
||||
|
||||
|
||||
|
||||
#include <wx/app.h>
|
||||
#include <wx/cmdline.h>
|
||||
#include <wx/timer.h>
|
||||
#include <wx/string.h>
|
||||
#include <thread>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <future>
|
||||
|
||||
|
||||
|
||||
class Emulator;
|
||||
|
||||
|
||||
|
||||
class EmuTimer : public wxTimer {
|
||||
Emulator *emu;
|
||||
|
||||
public:
|
||||
EmuTimer(Emulator *e);
|
||||
virtual ~EmuTimer();
|
||||
|
||||
void Notify() override;
|
||||
|
||||
void begin();
|
||||
};
|
||||
|
||||
|
||||
|
||||
class E2wxApp : public wxApp {
|
||||
const std::string id;
|
||||
const wxString id;
|
||||
const wxString version;
|
||||
std::filesystem::path logfile;
|
||||
std::filesystem::path resdir;
|
||||
std::filesystem::path conffile;
|
||||
std::filesystem::path confdir;
|
||||
std::filesystem::path docsdir;
|
||||
wxString arg_configfile;
|
||||
EmuTimer *emu_timer;
|
||||
Emulator *emu;
|
||||
|
||||
const std::filesystem::path BuildLogFilePath() const;
|
||||
void InitBoostLog();
|
||||
|
||||
public:
|
||||
static std::promise<void> barrier_to_init;
|
||||
|
||||
E2wxApp();
|
||||
virtual ~E2wxApp();
|
||||
|
||||
const std::string GetID() const;
|
||||
const wxString GetID() const;
|
||||
const wxString GetVersion() const;
|
||||
const std::filesystem::path GetLogFile() const;
|
||||
const std::filesystem::path GetResDir() const;
|
||||
@ -58,10 +80,12 @@ public:
|
||||
virtual bool OnInit() override;
|
||||
virtual int OnExit() override;
|
||||
virtual void OnFatalException() override;
|
||||
// virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
|
||||
// virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
|
||||
virtual void OnInitCmdLine(wxCmdLineParser& parser) override;
|
||||
virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override;
|
||||
};
|
||||
|
||||
wxDECLARE_APP(E2wxApp);
|
||||
|
||||
|
||||
|
||||
#endif /* E2WXAPP_H */
|
||||
|
@ -32,6 +32,8 @@ timable(0), // No ticked object (NULL pointer)
|
||||
quit(false),
|
||||
repeat(false),
|
||||
keysDown(0),
|
||||
skip(0),
|
||||
prev_ms(SDL_GetTicks()),
|
||||
command(false),
|
||||
pendingCommandExit(false) {
|
||||
}
|
||||
@ -162,37 +164,38 @@ void Emulator::handleAnyPendingEvents() {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// The core of this Apple
|
||||
int Emulator::run() {
|
||||
int skip = 0;
|
||||
Uint32 prev_ms = SDL_GetTicks();
|
||||
|
||||
// While the user still wants to run this emulation...
|
||||
while (!this->quit) {
|
||||
// (Obligatory protection against NULL object pointer)
|
||||
tick();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void Emulator::tick() {
|
||||
if (this->timable) {
|
||||
this->timable->tick();
|
||||
this->timable->tick(); // this runs the emulator!
|
||||
handleRepeatKey();
|
||||
}
|
||||
|
||||
// People who have too many press releases should be referred to as
|
||||
// keyboards
|
||||
|
||||
if (CHECK_EVERY_CYCLE <= ++skip) {
|
||||
if (CHECK_EVERY_CYCLE <= ++this->skip) {
|
||||
// ...then it's time to drain away any piled-up user interaction
|
||||
// events that SDL has stored up for us
|
||||
// Reload the skip quantity
|
||||
skip = 0;
|
||||
this->skip = 0;
|
||||
|
||||
handleAnyPendingEvents();
|
||||
|
||||
// If we're trying to run as slow as a real Apple ][...
|
||||
if (!this->fhyper.isHyper()) {
|
||||
const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - prev_ms);
|
||||
const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - this->prev_ms);
|
||||
if (0 < delta_ms && delta_ms <= EXPECTED_MS) {
|
||||
SDL_Delay(delta_ms);
|
||||
}
|
||||
@ -201,17 +204,26 @@ int Emulator::run() {
|
||||
|
||||
// Display the current estimate of the emulator's actual speed
|
||||
// performance
|
||||
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - prev_ms));
|
||||
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - this->prev_ms));
|
||||
|
||||
prev_ms = SDL_GetTicks();
|
||||
this->prev_ms = SDL_GetTicks();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
void Emulator::tick50ms() {
|
||||
if (this->timable) {
|
||||
for (int i = 0; i < CHECK_EVERY_CYCLE; ++i) {
|
||||
this->timable->tick(); // this runs the emulator!
|
||||
handleRepeatKey();
|
||||
}
|
||||
}
|
||||
handleAnyPendingEvents();
|
||||
this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - this->prev_ms));
|
||||
this->prev_ms = SDL_GetTicks();
|
||||
// TODO: how to check this->quit ?
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -52,10 +52,14 @@ class Emulator
|
||||
int keysDown;
|
||||
int rept;
|
||||
unsigned char lastKeyDown;
|
||||
int skip;
|
||||
Uint32 prev_ms;
|
||||
bool command;
|
||||
bool pendingCommandExit;
|
||||
std::string cmdline;
|
||||
|
||||
void tick();
|
||||
|
||||
void dispatchKeypress(const SDL_KeyboardEvent& keyEvent);
|
||||
void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent);
|
||||
void cmdKey(const SDL_KeyboardEvent& keyEvent);
|
||||
@ -80,6 +84,7 @@ public:
|
||||
void quitIfSafe();
|
||||
|
||||
virtual int run();
|
||||
void tick50ms();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
76
src/main.cpp
76
src/main.cpp
@ -1,6 +1,7 @@
|
||||
/*
|
||||
epple2
|
||||
Copyright (C) 2008, 2022 by Christopher A. Mosher <cmosher01@gmail.com>
|
||||
|
||||
Copyright (C) 2008, 2022 by Christopher A. Mosher, <cmosher01@gmail.com> https://mosher.mine.nu https://github.com/cmosher01
|
||||
|
||||
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
|
||||
@ -16,81 +17,16 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "e2const.h"
|
||||
#include "emulator.h"
|
||||
#include "configep2.h"
|
||||
#include "gui.h"
|
||||
#include "e2const.h"
|
||||
#include "E2wxApp.h"
|
||||
|
||||
#include <wx/app.h>
|
||||
|
||||
#include <thread>
|
||||
#include <future>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstddef>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static std::string parse_args(int argc, char* argv[]) {
|
||||
if (argc > 2) {
|
||||
throw std::runtime_error("usage: epple2 [config-file]" );
|
||||
}
|
||||
|
||||
if (argc <= 1) {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
return std::string(argv[1]);
|
||||
}
|
||||
|
||||
|
||||
static int fake_argc(1);
|
||||
static char fake_prog[] = "epple2";
|
||||
static char *fake_argv[] { fake_prog };
|
||||
|
||||
static int runWx() {
|
||||
std::cout << "starting wx..." << std::endl;
|
||||
return wxEntry(fake_argc, fake_argv);
|
||||
}
|
||||
|
||||
static int runSdl(const std::string config_file) {
|
||||
GUI gui;
|
||||
|
||||
std::future<void> barrier_to_app_init = E2wxApp::barrier_to_init.get_future();
|
||||
|
||||
std::thread thread_wx(runWx);
|
||||
|
||||
std::cout << "wait for wx init" << std::endl;
|
||||
const std::future_status fut = barrier_to_app_init.wait_for(10s);
|
||||
if (fut == std::future_status::timeout) {
|
||||
std::cerr << "timed-out waiting for wx to finish initializing" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cout << "wx init finished" << std::endl;
|
||||
|
||||
std::unique_ptr<Emulator> emu(new Emulator());
|
||||
|
||||
Config cfg(config_file);
|
||||
emu->config(cfg);
|
||||
|
||||
emu->init();
|
||||
|
||||
const int ret = emu->run();
|
||||
|
||||
if (wxApp::GetInstance() != nullptr) {
|
||||
wxApp::GetInstance()->ExitMainLoop();
|
||||
}
|
||||
thread_wx.join();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
@ -106,9 +42,7 @@ int main(int argc, char *argv[]) {
|
||||
throw std::runtime_error("bad constant in e2const.h" );
|
||||
}
|
||||
|
||||
const std::string config_file = parse_args(argc, argv);
|
||||
GUI gui;
|
||||
|
||||
const int ret = runSdl(config_file);
|
||||
|
||||
return ret;
|
||||
return wxEntry(argc, argv);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user