--- nono/wx/wxmainframe.cpp 2026/04/29 17:05:44 1.1.1.22 +++ nono/wx/wxmainframe.cpp 2026/04/29 17:05:58 1.1.1.25 @@ -13,17 +13,20 @@ #include "wxaccstatmonitor.h" #include "wxdipswwindow.h" #include "wxdumpmonitor.h" +#include "wxgvrammonitor.h" #include "wxlcdwindow.h" #include "wxlogmonitor.h" #include "wxlogsetting.h" #include "wxmainview.h" #include "wxmonitor.h" #include "wxmpumonitor.h" +#include "wxpagetablemonitor.h" #include "wxpalettemonitor.h" -#include "wxplanemonitor.h" #include "wxromwindow.h" #include "wxsoftkey.h" #include "wxstatuspanel.h" +#include "wxthreadmonitor.h" +#include "wxtvrammonitor.h" #include "wxuimessage.h" #include "wxversion.h" #include "config.h" @@ -31,6 +34,7 @@ #include "fdd.h" #include "hostcom.h" #include "hostnet.h" +#include "hostsound.h" #include "mainapp.h" #include "mpu.h" #include "netdriver_slirp.h" @@ -41,10 +45,10 @@ #include "syncer.h" #include -// ID は 0 から (wxID_LOWEST = 5000 未満まで) 使えるっぽい。 +// ID は 1 から (wxID_LOWEST = 5000 未満まで) 使えるっぽい +// (wxGTK は 0 から使用可能だが wxOSX は 0 が不可)。 // メニュー ID のうちウィンドウのオープン状態を維持する必要があるものは -// (ID が 0 から使えるのなら) 0 から割り当てて配列で管理してしまうのが -// 手っ取り早い。 +// 0 (付近) から割り当てて 0 から始まる配列で管理してしまうのが手っ取り早い。 // ウィンドウに割り当てるウィンドウ ID とメニューイベントで飛んでくる // メニュー ID は互いに干渉しないはずなので、同じ値を使うことでメニューと // ウィンドウの紐付けをする。 @@ -123,6 +127,13 @@ enum { ID_HOSTCOM_DBG_CONSOLE, // 存在しないけど HOSTCOMn と揃える必要がある。 ID_HOSTCOM_DBG_NONE, // 最後に置くこと。 + ID_HOSTSOUND_START, + ID_HOSTSOUND_NETBSD, + ID_HOSTSOUND_SNDIO, + ID_HOSTSOUND_ALSA, + ID_HOSTSOUND_WAV, + ID_HOSTSOUND_NONE, // 最後に置くこと + ID_SCALE_START, ID_SCALE_END = ID_SCALE_START + 6, @@ -224,6 +235,10 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit WXMainFrame::OnMenuHostCom) EVT_UPDATE_UI_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, WXMainFrame::OnMenuHostComUI) + EVT_MENU_RANGE(ID_HOSTSOUND_START + 1, ID_HOSTSOUND_NONE, + WXMainFrame::OnMenuHostSound) + EVT_UPDATE_UI_RANGE(ID_HOSTSOUND_START + 1, ID_HOSTSOUND_NONE, + WXMainFrame::OnMenuHostSoundUI) EVT_MENU_RANGE(ID_SCALE_START, ID_SCALE_END, WXMainFrame::OnMenuScale) @@ -294,6 +309,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren hostcom[i] = gMainApp.FindObject(OBJ_HOSTCOM(i)); } hostcom_dbg = gMainApp.FindObject(OBJ_HOSTCOM_DBG); + hostsound = gMainApp.FindObject(OBJ_HOSTSOUND); // メイン MPU 名を取得。メニューとタイトルによく出てくるので。 // "88xx0" とか "88200" は別処理。 @@ -341,6 +357,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren for (uint i = 0; i < hostcom.size(); i++) { CreateHostComMenu(menuSet, i); } + CreateHostSoundMenu(menuSet); menubar->Append(menuSet, _("&Setting")); // メニュー > 表示 @@ -426,6 +443,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxMenu *menuMPU = new wxMenu(); AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Registers")); AppendIf(menuMPU, ID_MONITOR_MPUATC, "&ATC"); + AppendIf(menuMPU, ID_SUBWIN_MPUPT, _("&Page Table")); AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("&Caches")); AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupts")); AppendIfSeparator(menuMPU, VMCap::M88K); @@ -517,15 +535,17 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuDev, ID_MONITOR_VIRTIO_NET, _("VirtIO Network")); AppendIf(menuDev, ID_MONITOR_VIRTIO_SCSI, "VirtIO SCSI"); AppendIf(menuDev, ID_MONITOR_VIRTIO_ENTROPY,_("VirtIO Entropy")); - AppendIf(menuDev, ID_MONITOR_CRTC, "CRTC"); + AppendIf(menuDev, ID_MONITOR_CRTC, _("CRTC and Video Controller")); AppendIf(menuDev, ID_MONITOR_LUNAVC, _("Video Control")); AppendIf(menuDev, ID_MONITOR_BT45x, "Bt454/458"); AppendIf(menuDev, ID_SUBWIN_PALETTE, _("Palette Colormap")); - AppendIf(menuDev, ID_SUBWIN_TEXTPAL, _("Text Palette Colormap")); AppendIf(menuDev, ID_MONITOR_RENDERER, _("Renderer")); AppendIf(menuDev, ID_SUBWIN_LUNAFB, _("Bitmap Plane")); - AppendIf(menuDev, ID_SUBWIN_TVRAM, _("Text VRAM")); + AppendIf(menuDev, ID_SUBWIN_TVRAM, _("Text Screen")); + AppendIf(menuDev, ID_SUBWIN_GVRAM, _("Graphic Screen")); + AppendIf(menuDev, ID_MONITOR_SOUND, _("Sound")); AppendIf(menuDev, ID_MONITOR_SSG, "SSG"); + AppendIf(menuDev, ID_MONITOR_ADPCM, "ADPCM"); AppendIf(menuDev, ID_MONITOR_ROMCONS, _("ROM Console (provisional)")); AppendIf(menuDev, ID_SUBWIN_ROM, "ROM"); // LUNA はバスが複数あるので Mainbus Device とする。 @@ -538,6 +558,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxMenu *menuHost = new wxMenu(); AppendIf(menuHost, ID_MONITOR_WXHOSTINFO, _("Host &Information")); + AppendIf(menuHost, ID_SUBWIN_THREADS, _("Thread Status")); for (uint i = 0; i < hostnet.size(); i++) { uint id = ID_MONITOR_HOSTNET(i); if (gMonitorManager->Find(id)) { @@ -551,10 +572,11 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuHost->AppendCheckItem(id, GetHostComLabel(i)); } } + AppendIf(menuHost, ID_MONITOR_HOSTSOUND, _("Host Sound")); menuMonitor->AppendSubMenu(menuHost, _("&Host")); wxMenu *menuDebug = new wxMenu(); - AppendIf(menuDebug, ID_SUBWIN_LOG, _("&Log")); + AppendIf(menuDebug, ID_MONITOR_LOG, _("&Log")); AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoints")); menuDebug->AppendSeparator(); AppendIf(menuDebug, ID_SUBWIN_LOGSETTING, _("Log Level &Setting")); @@ -615,8 +637,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren // SHOW イベントを最初にも一度起こしたいため // ステータスパネルを一旦非表示にする (これで SHOW(false) イベントが飛ぶ) statuspanel->Hide(); - const ConfigItem& item_show = gConfig->Find("show-statuspanel"); - if (item_show.AsInt() != 0) { + if (gConfig->Find("show-statuspanel").AsBool()) { // 必要なら改めて表示 (これで SHOW(true) イベントが飛ぶ) statuspanel->Show(); } @@ -627,10 +648,10 @@ WXMainFrame::WXMainFrame(wxWindow *paren // 来た or 外れたことを示すので、wxFrame (というかたぶん wxTopLevelWindow) // を継承している WXMainFrameに飛んでくるのだが、処理の都合上 WXMainView で // 扱いたいので、そちらに回す。 - Connect(wxEVT_ACTIVATE, wxActivateEventHandler(WXMainView::OnActivate), - NULL, mainview); + Bind(wxEVT_ACTIVATE, &WXMainView::OnActivate, mainview); // ウィンドウ表示後に続きの処理をするための単発アイドルイベント。 + // こっちは Disconnect() するので Bind() は使えない。 Connect(wxEVT_IDLE, wxIdleEventHandler(WXMainFrame::OnIdle)); // VM からの通知を接続 @@ -644,6 +665,8 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); WXUIMessage::Connect(UIMessage::HOSTCOM_FAILED, this, wxCommandEventHandler(WXMainFrame::OnHostComFailed)); + WXUIMessage::Connect(UIMessage::HOSTSOUND_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostSoundFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Connect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -662,6 +685,8 @@ WXMainFrame::~WXMainFrame() wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); WXUIMessage::Disconnect(UIMessage::HOSTCOM_FAILED, this, wxCommandEventHandler(WXMainFrame::OnHostComFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTSOUND_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostSoundFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Disconnect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -767,6 +792,29 @@ WXMainFrame::CreateHostComMenu(wxMenu *m menuSet->AppendSubMenu(menu, name); } +// HostSound 用のメニューを作成して menuSet に追加する。 +void +WXMainFrame::CreateHostSoundMenu(wxMenu *menuSet) +{ + if (hostsound == NULL) { + return; + } + + wxMenu *menu = new wxMenu(); +#if defined(HAVE_HOSTSOUND_NETBSD) + menu->AppendRadioItem(ID_HOSTSOUND_NETBSD, "&netbsd"); +#endif +#if defined(HAVE_HOSTSOUND_SNDIO) + menu->AppendRadioItem(ID_HOSTSOUND_SNDIO, "&sndio"); +#endif +#if defined(HAVE_HOSTSOUND_ALSA) + menu->AppendRadioItem(ID_HOSTSOUND_ALSA, "&alsa"); +#endif + menu->AppendRadioItem(ID_HOSTSOUND_WAV, "&wav"); + menu->AppendRadioItem(ID_HOSTSOUND_NONE, "&none"); + menuSet->AppendSubMenu(menu, "HostSound"); +} + // リムーバブルデバイス用のメニューを作成して menuDevice に追加する void WXMainFrame::CreateRemovableMenu(wxMenu *menuDevice) @@ -859,6 +907,8 @@ WXMainFrame::Init() return false; } + statuspanel->Init(); + return true; } @@ -928,7 +978,7 @@ WXMainFrame::OnIdle(wxIdleEvent& ev) { // UIMessage の処理を開始する。 // 少なくとも WXMainFrame のコンストラクタが完了した後のほうがいいはず。 - UIMessage::Attach(&WXUIMessage::Process); + gMainApp.GetUIMessage()->StartUIMessage(&WXUIMessage::Process); // ウィンドウを表示 for (int i = 0; i < subwindow_start.size(); i++) { @@ -948,6 +998,8 @@ WXMainFrame::OnIdle(wxIdleEvent& ev) void WXMainFrame::OnClose(wxCloseEvent& event) { + // UIMessage を停止 + gMainApp.GetUIMessage()->StopUIMessage(); // ステータスパネルの更新を停止 statuspanel->Close(); // メインビューの描画を停止 @@ -1038,10 +1090,10 @@ WXMainFrame::OnFullSpeed(wxCommandEvent& { if (event.IsChecked()) { // チェックが入ったので、高速モードにする - syncer->RequestFullSpeed(true); + syncer->NotifyFullSpeed(true); } else { // チェックが消えたので、通常モードにする - syncer->RequestFullSpeed(false); + syncer->NotifyFullSpeed(false); } } @@ -1217,6 +1269,49 @@ WXMainFrame::OnMenuHostComUI(wxUpdateUIE event.Check((id == selected)); } +// メニューの「設定 > HostSound > *」の選択肢イベント +void +WXMainFrame::OnMenuHostSound(wxCommandEvent& event) +{ + // 設定を更新。 + std::string line = "hostsound-driver="; + switch (event.GetId()) { + case ID_HOSTSOUND_NETBSD: line += "netbsd"; break; + case ID_HOSTSOUND_SNDIO: line += "sndio"; break; + case ID_HOSTSOUND_ALSA: line += "alsa"; break; + case ID_HOSTSOUND_WAV: line += "wav"; break; + case ID_HOSTSOUND_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + hostsound->NotifyReselectDriver(); +} + +// メニューの「設定 > HostSound > *」の UI +void +WXMainFrame::OnMenuHostSoundUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + const std::string driver = hostsound->GetDriverName(); + int selected; + if (driver == "netbsd") { + selected = ID_HOSTSOUND_NETBSD; + } else if (driver == "sndio") { + selected = ID_HOSTSOUND_SNDIO; + } else if (driver == "alsa") { + selected = ID_HOSTSOUND_ALSA; + } else if (driver == "wav") { + selected = ID_HOSTSOUND_WAV; + } else { + selected = ID_HOSTSOUND_NONE; + } + + event.Check((id == selected)); +} + // hostnet ドライバ起動失敗のメッセージ。 void WXMainFrame::OnHostNetFailed(wxCommandEvent& event) @@ -1230,6 +1325,7 @@ WXMainFrame::OnHostNetFailed(wxCommandEv HostDriverFailed(hostdev, errmsg); } +// hostcom ドライバ起動失敗のメッセージ。 void WXMainFrame::OnHostComFailed(wxCommandEvent& event) { @@ -1247,6 +1343,16 @@ WXMainFrame::OnHostComFailed(wxCommandEv HostDriverFailed(hostdev, errmsg); } +// hostsound ドライバ起動失敗のメッセージ +void +WXMainFrame::OnHostSoundFailed(wxCommandEvent& event) +{ + wxString errmsg; + + errmsg = hostsound->GetErrmsg(); + HostDriverFailed("hostsound", errmsg); +} + // ホストドライバ起動失敗のメッセージ。 void WXMainFrame::HostDriverFailed(const wxString& hostdev, const wxString& errmsg) @@ -1411,7 +1517,7 @@ WXMainFrame::OnMenuMonRate(wxCommandEven int idx = event.GetId() - ID_MONRATE_START; monitor_rate = monrates[idx]; - // アクティブなサブウィンドウのテキストパネル全員に通知 + // アクティブなサブウィンドウのモニタパネル全員に通知。 for (int i = 0; i < ID_SUBWIN_MAX; i++) { if ((bool)windows[i]) { auto *subwin = dynamic_cast(windows[i].get()); @@ -1712,6 +1818,10 @@ WXMainFrame::DoWindow(int id, bool enabl } catch (...) { } break; + case ID_MONITOR_ADPCM: + SetMonitor(id, "ADPCM"); + break; + case ID_MONITOR_AREASET: SetMonitor(id, _("Areaset")); break; @@ -1767,7 +1877,7 @@ WXMainFrame::DoWindow(int id, bool enabl } case ID_MONITOR_CRTC: - SetMonitor(id, "CRTC"); + SetMonitor(id, _("CRTC and Video Controller")); break; case ID_MONITOR_DMAC: @@ -1795,6 +1905,10 @@ WXMainFrame::DoWindow(int id, bool enabl break; } + case ID_MONITOR_HOSTSOUND: + SetMonitor(id, _("Host Sound")); + break; + case ID_MONITOR_INTERRUPT: { wxString name; @@ -1822,6 +1936,12 @@ WXMainFrame::DoWindow(int id, bool enabl } catch (...) { } break; + case ID_MONITOR_LOG: + try { + windows[id].reset(new WXLogMonitor(this)); + } catch (...) { } + break; + case ID_MONITOR_LUNAVC: SetMonitor(id, _("Video Control")); break; @@ -1930,6 +2050,10 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, _("SLIRP Internal States")); break; + case ID_MONITOR_SOUND: + SetMonitor(id, _("Sound")); + break; + case ID_MONITOR_SPC: SetMonitor(id, "SPC (MB89352)"); break; @@ -2037,15 +2161,15 @@ WXMainFrame::DoWindow(int id, bool enabl } catch (...) { } break; - case ID_SUBWIN_LCDPANEL: + case ID_SUBWIN_GVRAM: try { - windows[id].reset(new WXLCDWindow(this)); + windows[id].reset(new WXGVRAMWindow(this, _("Graphic Screen"))); } catch (...) { } break; - case ID_SUBWIN_LOG: + case ID_SUBWIN_LCDPANEL: try { - windows[id].reset(new WXLogMonitor(this)); + windows[id].reset(new WXLCDWindow(this)); } catch (...) { } break; @@ -2063,14 +2187,31 @@ WXMainFrame::DoWindow(int id, bool enabl if (id == ID_SUBWIN_LUNAFB) { name = _("Bitmap Plane"); } else { - name = _("Text VRAM"); + name = _("Text Screen"); } try { - windows[id].reset(new WXPlaneVRAMWindow(this, name)); + windows[id].reset(new WXTVRAMWindow(this, name)); } catch (...) { } break; } + case ID_SUBWIN_MPUPT: + { + wxString name = MPUName() + " " + _("Page Table"); + if (MPUName() == "MC68030") { + try { + windows[id].reset(new WXPageTable68030Window(this, name)); + } catch (...) { } + } else if (MPUName() == "MC68040") { + try { + windows[id].reset(new WXPageTable68040Window(this, name)); + } catch (...) { } + } else { + // not supported + } + break; + } + case ID_SUBWIN_NEWSIO: try { windows[id].reset(new WXScrollMonitorWindow(this, @@ -2080,20 +2221,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_SUBWIN_PALETTE: - case ID_SUBWIN_TEXTPAL: - { - // 呼び方が違うので名前と ID が違う - wxString name; - if (id == ID_SUBWIN_TEXTPAL) { - name = _("Text Palette Colormap"); - } else { - name = _("Palette Colormap"); - } try { - windows[id].reset(new WXPaletteWindow(this, name)); + windows[id].reset(new WXPaletteWindow(this, + _("Palette Colormap"))); } catch (...) { } break; - } case ID_SUBWIN_ROM: try { @@ -2108,6 +2240,12 @@ WXMainFrame::DoWindow(int id, bool enabl } catch (...) { } break; + case ID_SUBWIN_THREADS: + try { + windows[id].reset(new WXThreadMonitorWindow(this)); + } catch (...) { } + break; + case ID_SUBWIN_VECTOR: { wxString name = MPUName() + " " + _("Vector Table");