--- nono/wx/wxapp.cpp 2026/04/29 17:05:04 1.1.1.10 +++ nono/wx/wxapp.cpp 2026/04/29 17:05:16 1.1.1.13 @@ -4,15 +4,19 @@ // Licensed under nono-license.txt // -#include "wxdumpmonitor.h" +// +// wx アプリケーションのエントリポイント +// + +#include "fontmanager.h" +#include "wxlogsetting.h" #include "wxmainframe.h" #include "wxmainview.h" -#include "wxtextpanel.h" +#include "wxuimessage.h" #include "wxversion.h" +#include "config.h" #include "mainapp.h" -#include "mpu680x0.h" -#include "mpu88xx0.h" -#include "scheduler.h" +#include "memdump.h" #include #include @@ -20,25 +24,33 @@ class WXApp : public wxApp { using inherited = wxApp; public: - bool OnInit(); + ~WXApp() override; + bool OnInit() override; int OnRun() override; private: bool ParseMonitors(const wxString& str); + bool ParseMemdumpValue(int id, const std::string&, const std::string&); void ShowMonitorsName(); int SearchMonitorName(const char *name); + int FindAvailable(const std::vector& candidates, + const std::string& name, int basenum, int count) const; wxLocale locale; + + std::unique_ptr pFontManager {}; + std::unique_ptr pHostInfo {}; }; // IMPLEMENT_APP() は闇マクロすぎて clang のちからには耐えられない -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Weverything" -#endif +PRAGMA_PUSH_WARNINGS IMPLEMENT_APP(WXApp) -#if defined(__clang__) -#pragma clang diagnostic pop -#endif +PRAGMA_POP_WARNINGS + +WXApp::~WXApp() +{ + // 開発用 + WXUIMessage::AssertAllDisconnected(); +} bool WXApp::OnInit() @@ -59,7 +71,7 @@ WXApp::OnRun() // 環境変数 $NONO_BUILD_HOME が定義されていればカタログ検索パスに // $NONO_BUILD_HOME/po を追加する (システムパスより前に挿入される)。 // カタログ開発時にワークツリーにあるカタログを見るため。 - locale.Init(wxLANGUAGE_DEFAULT); + locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT); const char *build_home = getenv("NONO_BUILD_HOME"); if (build_home) { wxString path(build_home); @@ -68,28 +80,37 @@ WXApp::OnRun() } locale.AddCatalog("nono"); - // --fontsize テキスト系コントロールのフォントサイズ - // 紛らわしいが ::global_fontsize は 12, 16 とかいう値。 - // WXTextPanel::global_fontsize (FontId) は enum 値。 + // テキスト系コントロールのフォントサイズ。 + // 紛らわしいが設定の monitor-fontsize は 12, 16 とかいう値。 + // FontManager::fontid は enum 値。 + const ConfigItem& item_fontsize = gConfig->Find("monitor-fontsize"); + int fontsize = item_fontsize.AsInt(); FontId fontid; - switch (gMainApp.fontsize) { + switch (fontsize) { case 12: fontid = FontId::_6x12; break; case 16: fontid = FontId::_8x16; break; + case 24: + fontid = FontId::_12x24; + break; default: - warnx("invalid fontsize: %d", gMainApp.fontsize); + item_fontsize.Err("Must be either 12, 16 or 24"); return EXIT_FAILURE; } - WXTextPanel::global_fontid = fontid; - - // グローバルオブジェクト (どこでやるのがいいか) - gHostInfo.reset(new HostInfoMonitor()); + pFontManager.reset(new FontManager()); + gFontManager = pFontManager.get(); + gFontManager->SetFont(fontid); + + // ホスト情報用のモニタ (どこでやるのがいいか) + pHostInfo.reset(new HostInfoMonitor()); + gHostInfo = pHostInfo.get(); + // 手順 4. (vm/device.h) // これ以降モニタの登録をしてはいけない。 - gMonitorManager.Fix(); + gMonitorManager->Fix(); // -M 起動時に表示するモニタ if (!gMainApp.monitor_opt.empty()) { @@ -98,8 +119,28 @@ WXApp::OnRun() } } - // -s screen scale - WXMainView::screen_scale = gMainApp.screen_scale; + // メインスクリーン倍率 + const ConfigItem& item_scale = gConfig->Find("mainview-scale"); + double scale; + if (item_scale.TryDouble(&scale) == false) { + item_scale.Err(); + return EXIT_FAILURE; + } + // 制限は適当 + if (scale <= 0 || scale >= 10) { + item_scale.Err(); + return EXIT_FAILURE; + } + WXMainView::screen_scale = scale; + + // モニター更新間隔 + const ConfigItem& item_rate = gConfig->Find("monitor-rate"); + int rate = item_rate.AsInt(); + if (rate < 1 || rate > 60) { + item_rate.Err(); + return EXIT_FAILURE; + } + WXMainFrame::SetMonitorRate(rate); // 引数処理が終わったので、スレッド作成を伴う初期化。 if (!gMainApp.Init2()) { @@ -107,12 +148,12 @@ WXApp::OnRun() } // メインウィンドウ - gMainFrame = new WXMainFrame(NULL); - gMainFrame->Show(true); - SetTopWindow(gMainFrame); + auto mainframe = new WXMainFrame(NULL); + mainframe->Show(true); + SetTopWindow(mainframe); // 設定反映などの初期化 - if (!gMainFrame->Init()) { + if (!mainframe->Init()) { return EXIT_FAILURE; } @@ -159,22 +200,85 @@ WXApp::ParseMonitors(const wxString& str WXMainFrame::subwindow_start[id] = true; // 値付き memdump の処理 - if (IS_MONITOR_MEMDUMP(id) && value.empty() == false) { - char *end; - errno = 0; - unsigned long u = strtoul(value.c_str(), &end, 16); - if (end == optarg || end[0] != '\0') { - warnx("%s: syntax error on monitor address", value.c_str()); - return -1; + if ((IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id)) + && value.empty() == false) + { + if (ParseMemdumpValue(id, name, value) == false) { + return false; + } + } + } + return true; +} + +// -Mmemdump= の続きの文字列 value を解析してセットする。 +// 書式は [.] +// fmt は B/W/L と M(MMU)、I(dIsasm)、Z(XPdisasm) +bool +WXApp::ParseMemdumpValue(int id, + const std::string& name, const std::string& value) +{ + auto mon = gMonitorManager->Get(id); + auto memdump = dynamic_cast(mon.obj); + assert(memdump); + + errno = 0; + char *end; + unsigned long u = strtoul(value.c_str(), &end, 16); + // これが呼ばれた時点で value は空ではないはず + if (errno == ERANGE || u > 0xffffffff) { + errno = ERANGE; + warn("-M %s=%s", name.c_str(), value.c_str()); + return false; + } + // アドレスを設定 + memdump->SetAddr((uint32)u); + + // さらに後ろがあれば表示形式指定。 + if (*end != '\0') { + if (*end++ != '.') { + goto usage; + } + + if (end[1] != '\0') { + goto usage; + } + + Memdump::Format fmt; + switch (std::toupper((int)*end)) { + case 'B': fmt = Memdump::Byte; break; + case '\0': + case 'W': fmt = Memdump::Word; break; + case 'L': fmt = Memdump::Long; break; + case 'M': + if (gMainApp.Has(VMCap::M88K)) { + fmt = Memdump::M88200Page; + } else { + // ロングは指定できないけど使われてないので放置 + fmt = Memdump::M68030PageShort; } - if (errno == ERANGE || u > 0xffffffff) { - errno = ERANGE; - warn("%s", value.c_str()); - return -1; + break; + case 'I': + if (gMainApp.Has(VMCap::M88K)) { + fmt = Memdump::M88100Disasm; + } else { + fmt = Memdump::M68030Disasm; } - WXMemdumpWindow::SetStickyAddr(id, (uint32)u); + break; + case 'Z': + fmt = Memdump::HD64180Disasm; + break; + default: + usage: + warnx("-M %s=%s: syntax error; syntax is \"[.]\"", + name.c_str(), value.c_str()); + return false; } + + // 表示形式を設定 + memdump->SetFormat(fmt); } + return true; } @@ -187,14 +291,14 @@ WXApp::ShowMonitorsName() // モニターは登録されていれば列挙 // (登録されているものを全部列挙ではないことに注意) for (int id = ID_MONITOR_START; id <= ID_MONITOR_END; id++) { - if (gMonitorManager.Find(id)) { + if (gMonitorManager->Find(id)) { list.push_back(id); } } // サブウィンドウは機種情報から判断 for (int id = ID_SUBWIN_START; id <= ID_SUBWIN_END; id++) { - vmf_t feature = gMonitorManager.GetFeature(id); - if (gMainApp.HasVMFeature(feature)) { + VMCap vmcap = gMonitorManager->GetVMCap(id); + if (gMainApp.Has(vmcap)) { list.push_back(id); } } @@ -220,18 +324,18 @@ WXApp::SearchMonitorName(const char *nam for (int id = ID_MONITOR_START; id <= ID_SUBWIN_END; id++) { if (id < ID_SUBWIN_START) { // モニターは登録されていなければ除外する - if (gMonitorManager.Find(id) == NULL) { + if (gMonitorManager->Find(id) == NULL) { continue; } } else { // サブウィンドウは該当機種でなければ除外する - vmf_t feature = gMonitorManager.GetFeature(id); - if (gMainApp.HasVMFeature(feature) == false) { + VMCap vmcap = gMonitorManager->GetVMCap(id); + if (gMainApp.Has(vmcap) == false) { continue; } } - const auto& aliases = gMonitorManager.GetAliases(id); + const auto& aliases = gMonitorManager->GetAliases(id); bool matched = false; for (const auto& alias : aliases) { @@ -262,22 +366,20 @@ WXApp::SearchMonitorName(const char *nam return candidates[0]; } else { // 候補が複数あった + int id; - // 候補が memdumpN のみなら無記名 memdump とする。 - bool is_memdump = std::all_of(candidates.begin(), candidates.end(), - [](int x) { return IS_MONITOR_MEMDUMP(x); } - ); - if (is_memdump) { - // この時点で空いてるものを返す - for (int i = 0; i < MAX_MEMDUMP_MONITOR; i++) { - int id = ID_MONITOR_MEMDUMP0 + i; - if (WXMainFrame::subwindow_start[id] == false) { - return id; - } - } - // 空きがなければエラー - warnx("No more memdump windows available"); - return -1; + // "memdump" を空いてる "memdump*" に割り当てる + id = FindAvailable(candidates, "memdump", + ID_MONITOR_MEMDUMP0, MAX_MEMDUMP_MONITOR); + if (id != 0) { + return id; + } + + // "xpmemdump" を空いてる "xpmemdump*" に割り当てる + id = FindAvailable(candidates, "xpmemdump", + ID_MONITOR_XPMEMDUMP0, MAX_XPMEMDUMP_MONITOR); + if (id != 0) { + return id; } // そうでなければ、候補を表示 @@ -291,3 +393,36 @@ WXApp::SearchMonitorName(const char *nam return -1; } } + +// candidates (候補の一覧) がすべて basenum .. count 内に入っていれば、 +// その中の空きウィンドウ ID を返す。 +// 空きがなければエラーメッセージを表示して - 1 を返す。 +// candidates の中に basenum .. count 内に入っていないものがあれば 0 を返す。 +// 今の所ここでターゲットにしている人たちに ID=0 はいないので。 +// start は ID_MONITOR_*0、count は MAX_*_MONITOR のほうで、 +// 最初と最後の ID ではないので注意。 +int +WXApp::FindAvailable(const std::vector& candidates, + const std::string& name, int start, int count) const +{ + // candidates がすべてこの start..end に入っているか + bool all = std::all_of(candidates.begin(), candidates.end(), + [&](int id) { return (start <= id && id < start + count); } + ); + + if (all) { + // この時点で空いてるものを返す。 + for (int i = 0; i < count; i++) { + int id = start + i; + if (WXMainFrame::subwindow_start[id] == false) { + return id; + } + } + // 空きがなければエラー + warnx("No more %s windows available", name.c_str()); + return -1; + } + + // 候補が他にもあった + return 0; +}