--- nono/wx/wxmainframe.cpp 2026/04/29 17:05:40 1.1.1.21 +++ nono/wx/wxmainframe.cpp 2026/04/29 17:05:44 1.1.1.22 @@ -29,8 +29,11 @@ #include "config.h" #include "fdc.h" #include "fdd.h" +#include "hostcom.h" +#include "hostnet.h" #include "mainapp.h" #include "mpu.h" +#include "netdriver_slirp.h" #include "nmi.h" #include "power.h" #include "scsidev.h" @@ -82,6 +85,44 @@ enum { ID_INPUT_JP, ID_INPUT_END, + ID_HOSTNET0_START, + ID_HOSTNET0_USERMODE, + ID_HOSTNET0_TAP, + ID_HOSTNET0_BPF, + ID_HOSTNET0_AFPACKET, + ID_HOSTNET0_NONE, // 最後に置くこと + + ID_HOSTNET1_START, + ID_HOSTNET1_USERMODE, + ID_HOSTNET1_TAP, + ID_HOSTNET1_BPF, + ID_HOSTNET1_AFPACKET, + ID_HOSTNET1_NONE, // 最後に置くこと + + ID_HOSTCOM0_START, + ID_HOSTCOM0_TCP, + ID_HOSTCOM0_STDIO, + ID_HOSTCOM0_CONSOLE, + ID_HOSTCOM0_NONE, // 最後に置くこと + + ID_HOSTCOM1_START, + ID_HOSTCOM1_TCP, + ID_HOSTCOM1_STDIO, + ID_HOSTCOM1_CONSOLE, + ID_HOSTCOM1_NONE, // 最後に置くこと + + ID_HOSTCOM2_START, + ID_HOSTCOM2_TCP, + ID_HOSTCOM2_STDIO, + ID_HOSTCOM2_CONSOLE, + ID_HOSTCOM2_NONE, // 最後に置くこと + + ID_HOSTCOM_DBG_START, + ID_HOSTCOM_DBG_TCP, + ID_HOSTCOM_DBG_STDIO, + ID_HOSTCOM_DBG_CONSOLE, // 存在しないけど HOSTCOMn と揃える必要がある。 + ID_HOSTCOM_DBG_NONE, // 最後に置くこと。 + ID_SCALE_START, ID_SCALE_END = ID_SCALE_START + 6, @@ -174,6 +215,16 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit WXMainFrame::OnMenuInput) EVT_UPDATE_UI_RANGE(ID_INPUT_START + 1, ID_INPUT_END -1, WXMainFrame::OnMenuInputUI) + + EVT_MENU_RANGE(ID_HOSTNET0_START + 1, ID_HOSTNET1_NONE, + WXMainFrame::OnMenuHostNet) + EVT_UPDATE_UI_RANGE(ID_HOSTNET0_START + 1, ID_HOSTNET1_NONE, + WXMainFrame::OnMenuHostNetUI) + EVT_MENU_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, + WXMainFrame::OnMenuHostCom) + EVT_UPDATE_UI_RANGE(ID_HOSTCOM0_START + 1, ID_HOSTCOM2_NONE, + WXMainFrame::OnMenuHostComUI) + EVT_MENU_RANGE(ID_SCALE_START, ID_SCALE_END, WXMainFrame::OnMenuScale) EVT_UPDATE_UI_RANGE(ID_SCALE_START, ID_SCALE_END, @@ -218,6 +269,12 @@ wxBEGIN_EVENT_TABLE(WXMainFrame, inherit EVT_UPDATE_UI(ID_KEYBOARD_CONNECT, WXMainFrame::OnKeyboardConnectUI) EVT_MENU_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindow) EVT_UPDATE_UI_RANGE(0, ID_SUBWIN_END, WXMainFrame::OnWindowUI) + + EVT_MENU_RANGE(ID_HOSTCOM_DBG_START + 1, ID_HOSTCOM_DBG_NONE, + WXMainFrame::OnMenuHostCom) + EVT_UPDATE_UI_RANGE(ID_HOSTCOM_DBG_START + 1, ID_HOSTCOM_DBG_NONE, + WXMainFrame::OnMenuHostComUI) + EVT_MENU(wxID_ABOUT, WXMainFrame::OnAbout) wxEND_EVENT_TABLE() @@ -230,6 +287,13 @@ WXMainFrame::WXMainFrame(wxWindow *paren syncer = GetSyncer(); // デバイスを取得。こっちはあるかどうかを調べる keyboard = gMainApp.FindObject(OBJ_KEYBOARD); + for (uint i = 0; i < hostnet.size(); i++) { + hostnet[i] = gMainApp.FindObject(OBJ_HOSTNET(i)); + } + for (uint i = 0; i < hostcom.size(); i++) { + hostcom[i] = gMainApp.FindObject(OBJ_HOSTCOM(i)); + } + hostcom_dbg = gMainApp.FindObject(OBJ_HOSTCOM_DBG); // メイン MPU 名を取得。メニューとタイトルによく出てくるので。 // "88xx0" とか "88200" は別処理。 @@ -257,7 +321,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuVM->Append(ID_NMI_BUTTON, _("Push &Interrupt button")); } menuVM->AppendSeparator(); - menuVM->Append(ID_RESTART_VM, _("&Restart VM (For developers)"), ""); + menuVM->Append(ID_RESTART_VM, _("Re&start VM (For developers)"), ""); menuVM->AppendSeparator(); menuVM->Append(ID_EXIT, _("E&xit")); menubar->Append(menuVM, _("&VM")); @@ -271,6 +335,12 @@ WXMainFrame::WXMainFrame(wxWindow *paren menuSetInput->AppendRadioItem(ID_INPUT_JP, _("&JP Keyboard")); menuSet->AppendSubMenu(menuSetInput, _("&Key Input")); } + for (uint i = 0; i < hostnet.size(); i++) { + CreateHostNetMenu(menuSet, i); + } + for (uint i = 0; i < hostcom.size(); i++) { + CreateHostComMenu(menuSet, i); + } menubar->Append(menuSet, _("&Setting")); // メニュー > 表示 @@ -354,16 +424,18 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuMonitor, ID_MONITOR_SCHEDULER, _("&Scheduler")); wxMenu *menuMPU = new wxMenu(); - AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Register")); + AppendIf(menuMPU, ID_MONITOR_MPUREG, _("&Registers")); AppendIf(menuMPU, ID_MONITOR_MPUATC, "&ATC"); - AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("Cache")); - AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupt")); + AppendIf(menuMPU, ID_MONITOR_MPUCACHE, _("&Caches")); + AppendIf(menuMPU, ID_MONITOR_INTERRUPT, _("&Interrupts")); AppendIfSeparator(menuMPU, VMCap::M88K); - AppendIf(menuMPU, ID_MONITOR_CMMU7, "CMMU#7" + _("(Inst)")); + AppendIf(menuMPU, ID_MONITOR_CMMU7, + "CMMU#7" + _("(Inst)") + " " + _("Registers")); AppendIf(menuMPU, ID_MONITOR_ATC7, "ATC#7"); AppendIf(menuMPU, ID_SUBWIN_CACHE7, _("Cache") + "#7"); AppendIfSeparator(menuMPU, VMCap::M88K); - AppendIf(menuMPU, ID_MONITOR_CMMU6, "CMMU#6" + _("(Data)")); + AppendIf(menuMPU, ID_MONITOR_CMMU6, + "CMMU#6" + _("(Data)") + " " + _("Registers")); AppendIf(menuMPU, ID_MONITOR_ATC6, "ATC#6"); AppendIf(menuMPU, ID_SUBWIN_CACHE6, _("Cache") + "#6"); menuMPU->AppendSeparator(); @@ -379,16 +451,19 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxString mpulabel; if (gMainApp.Has(VMCap::M68K)) { mpulabel = "&MPU(" + mpuname + ")"; - } else { + } else if (gMainApp.Has(VMCap::M88K)) { mpulabel = "&MPU(MC88xx0)"; + } else { + mpulabel = "&MPU"; } menuMonitor->AppendSubMenu(menuMPU, mpulabel); if (gMainApp.Has(VMCap::LUNA)) { wxMenu *menuXP = new wxMenu(); - AppendIf(menuXP, ID_MONITOR_XPREG, _("&Register")); - AppendIf(menuXP, ID_MONITOR_XPINTR, _("&Interrupt")); + AppendIf(menuXP, ID_MONITOR_XPREG, _("&Registers")); + AppendIf(menuXP, ID_MONITOR_XPINTR, _("&Interrupts")); AppendIf(menuXP, ID_MONITOR_XPIO, _("Internal &Devices")); + AppendIf(menuXP, ID_MONITOR_XPASCI, "&ASCI"); menuXP->AppendSeparator(); for (uint i = 0; i < MAX_XPMEMDUMP_MONITOR; i++) { AppendIf(menuXP, ID_MONITOR_XPMEMDUMP(i), "memdump"); @@ -425,9 +500,9 @@ WXMainFrame::WXMainFrame(wxWindow *paren AppendIf(menuDev, ID_MONITOR_KEYBOARD, _("Keyboard/Mouse")); AppendIf(menuDev, ID_MONITOR_LANCE, "Lance"); AppendIf(menuDev, ID_MONITOR_NEREID, "Nereid"); - for (uint i = 0; i < 2; i++) { + for (uint i = 0; i < hostnet.size(); i++) { uint id = ID_MONITOR_RTL8019AS(i); - wxString name = string_format("Nereid(RTL8019AS) #%u", i); + wxString name = string_format("Nereid#%u (RTL8019AS)", i); AppendIf(menuDev, id, name); } AppendIf(menuDev, ID_MONITOR_SYSPORT, _("System Port")); @@ -456,37 +531,34 @@ WXMainFrame::WXMainFrame(wxWindow *paren // LUNA はバスが複数あるので Mainbus Device とする。 // 他の機種ではメインて言われても困るので Device とする。 if (gMainApp.Has(VMCap::LUNA)) { - menuMonitor->AppendSubMenu(menuDev, _("Mainbus De&vice")); + menuMonitor->AppendSubMenu(menuDev, _("Mainbus De&vices")); } else { - menuMonitor->AppendSubMenu(menuDev, _("De&vice")); + menuMonitor->AppendSubMenu(menuDev, _("De&vices")); } wxMenu *menuHost = new wxMenu(); AppendIf(menuHost, ID_MONITOR_WXHOSTINFO, _("Host &Information")); - if (gMainApp.IsX68030()) { - // X68030 ではネットワークは最大2つあるのでナンバリングが必要。 - // あれば表示ではなく、なければ Disable。 - for (uint i = 0; i < 2; i++) { - uint id = ID_MONITOR_HOSTNET(i); - wxString name = _("Host Network") + string_format(" #%u", i); - menuHost->AppendCheckItem(id, name); - if (gMonitorManager->Find(id) == NULL) { - menuHost->Enable(id, false); - } + for (uint i = 0; i < hostnet.size(); i++) { + uint id = ID_MONITOR_HOSTNET(i); + if (gMonitorManager->Find(id)) { + menuHost->AppendCheckItem(id, GetHostNetLabel(i)); } - } else { - // それ以外ではネットワークは1つ固定なのでナンバリング不要 - AppendIf(menuHost, ID_MONITOR_HOSTNET(0), _("Host Network")); } AppendIf(menuHost, ID_MONITOR_SLIRP, _("SLIRP Internal States")); - AppendIf(menuHost, ID_MONITOR_HOSTCOM, _("Host &Serial Port")); + for (uint i = 0; i < hostcom.size(); i++) { + uint id = ID_MONITOR_HOSTCOM(i); + if (gMonitorManager->Find(id)) { + menuHost->AppendCheckItem(id, GetHostComLabel(i)); + } + } menuMonitor->AppendSubMenu(menuHost, _("&Host")); wxMenu *menuDebug = new wxMenu(); AppendIf(menuDebug, ID_SUBWIN_LOG, _("&Log")); - AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoint")); + AppendIf(menuDebug, ID_MONITOR_BREAKPOINT, _("&Breakpoints")); menuDebug->AppendSeparator(); AppendIf(menuDebug, ID_SUBWIN_LOGSETTING, _("Log Level &Setting")); + CreateHostComMenu(menuDebug, -1); menuMonitor->AppendSubMenu(menuDebug, _("&Debug")); menubar->Append(menuMonitor, _("&Monitor")); @@ -513,7 +585,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren frame_title += wxString(vmname); frame_title += ')'; } - SetTitle(frame_title); + SetMyTitle(false); // UpdateUI イベントは Idle 時に時折チェックされるらしいが、 // (メインビューとサブウィンドウを合わせた) タイマーイベントの粒度が @@ -529,6 +601,16 @@ WXMainFrame::WXMainFrame(wxWindow *paren // mainview のほうを先に作成すること。 mainview = new WXMainView(this); statuspanel = new WXStatusPanel(this); + // 空き地用のパネル。 + spaceL = new WXBitmapPanel(this); + spaceR = new WXBitmapPanel(this); + spaceL->Hide(); + spaceR->Hide(); + + // Sizer 使わず自前でレイアウトする。 + SetAutoLayout(true); + // mainview のスケール、statuspanel のフォントサイズはいずれも + // コンストラクタの時点で初期状態がセットされている。 // SHOW イベントを最初にも一度起こしたいため // ステータスパネルを一旦非表示にする (これで SHOW(false) イベントが飛ぶ) @@ -539,8 +621,7 @@ WXMainFrame::WXMainFrame(wxWindow *paren statuspanel->Show(); } - // Sizer 使わず自前でレイアウトする。 - SetAutoLayout(true); + Fit(); // Activate イベントは、このトップレベルウィンドウにウィンドウフォーカスが // 来た or 外れたことを示すので、wxFrame (というかたぶん wxTopLevelWindow) @@ -559,6 +640,10 @@ WXMainFrame::WXMainFrame(wxWindow *paren wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Connect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); + WXUIMessage::Connect(UIMessage::HOSTNET_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); + WXUIMessage::Connect(UIMessage::HOSTCOM_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostComFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Connect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -573,6 +658,10 @@ WXMainFrame::~WXMainFrame() wxCommandEventHandler(WXMainFrame::OnInsertFailed)); WXUIMessage::Disconnect(UIMessage::FDD_MEDIA_FAILED, this, wxCommandEventHandler(WXMainFrame::OnInsertFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTNET_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostNetFailed)); + WXUIMessage::Disconnect(UIMessage::HOSTCOM_FAILED, this, + wxCommandEventHandler(WXMainFrame::OnHostComFailed)); if (gMainApp.Has(VMCap::M68K)) { WXUIMessage::Disconnect(UIMessage::HALT, this, wxCommandEventHandler(WXMainFrame::OnHaltNotify)); @@ -601,6 +690,83 @@ WXMainFrame::AppendIf(wxMenu *menu, int } } +// HostNet 用のメニューを作成して menuSet に追加する。 +void +WXMainFrame::CreateHostNetMenu(wxMenu *menuSet, uint unit) +{ + if (hostnet[unit] == NULL) { + return; + } + + int offset; + if (unit == 0) { + offset = ID_HOSTNET0_START - ID_HOSTNET0_START; + } else { + offset = ID_HOSTNET1_START - ID_HOSTNET0_START; + } + + wxMenu *menu = new wxMenu(); +#if defined(HAVE_HOSTNET_SLIRP) + menu->AppendRadioItem(offset + ID_HOSTNET0_USERMODE, "&usermode"); +#endif +#if defined(HAVE_HOSTNET_TAP) + menu->AppendRadioItem(offset + ID_HOSTNET0_TAP, "&tap"); +#endif +#if defined(HAVE_HOSTNET_BPF) + menu->AppendRadioItem(offset + ID_HOSTNET0_BPF, "&bpf"); +#endif +#if defined(HAVE_HOSTNET_AFPACKET) + menu->AppendRadioItem(offset + ID_HOSTNET0_AFPACKET, "&afpacket"); +#endif + menu->AppendRadioItem(offset + ID_HOSTNET0_NONE, "&none"); + menuSet->AppendSubMenu(menu, GetHostNetLabel(unit)); +} + +// HostCOM 用のメニューを作成して menuSet に追加する。 +// 引数の n は COM。ただし負数ならデバッガ用。 +void +WXMainFrame::CreateHostComMenu(wxMenu *menuSet, int n) +{ + HostCOMDevice *host; + + // デバッガ用は配列では最後。 + if (n < 0) { + host = hostcom_dbg; + } else { + host = hostcom[n]; + } + + if (host == NULL) { + return; + } + + int offset; + if (n == 0) { + offset = ID_HOSTCOM0_START - ID_HOSTCOM0_START; + } else if (n == 1) { + offset = ID_HOSTCOM1_START - ID_HOSTCOM0_START; + } else if (n == 2) { + offset = ID_HOSTCOM2_START - ID_HOSTCOM0_START; + } else { + offset = ID_HOSTCOM_DBG_START - ID_HOSTCOM0_START; + } + + wxMenu *menu = new wxMenu(); + menu->AppendRadioItem(offset + ID_HOSTCOM0_TCP, "&tcp"); + menu->AppendRadioItem(offset + ID_HOSTCOM0_STDIO, "&stdio"); + if (n >= 0 && gMainApp.FindObject(OBJ_CONSOLE)) { + menu->AppendRadioItem(offset + ID_HOSTCOM0_CONSOLE, "&console"); + } + menu->AppendRadioItem(offset + ID_HOSTCOM0_NONE, "&none"); + wxString name; + if (n >= 0) { + name = GetHostComLabel(n); + } else { + name = _("&Debugger"); + } + menuSet->AppendSubMenu(menu, name); +} + // リムーバブルデバイス用のメニューを作成して menuDevice に追加する void WXMainFrame::CreateRemovableMenu(wxMenu *menuDevice) @@ -696,32 +862,45 @@ WXMainFrame::Init() return true; } -bool -WXMainFrame::Layout() +void +WXMainFrame::Fit() { - if (inherited::Layout() == false) { - return false; + wxSize statsize(0, 0); + if (statuspanel->IsShown()) { + statsize = statuspanel->GetMinSize(); } + const wxSize& viewsize = mainview->GetSize(); - wxSize msize = statuspanel->GetMinClientSize(); - wxSize ssize = statuspanel->GetClientSize(); - wxSize vsize = mainview->GetClientSize(); + wxSize size(std::max(statsize.x, viewsize.x), statsize.y + viewsize.y); + SetClientSize(size); +} + +bool +WXMainFrame::Layout() +{ + const wxSize& client = GetClientSize(); + wxSize statsize(0, 0); if (statuspanel->IsShown()) { - ssize.y = msize.y; - } else { - ssize.y = 0; + statsize = statuspanel->GetSize(); + statuspanel->SetSize(0, 0, client.x, statsize.y); } - wxSize size; - size.x = std::max(msize.x, vsize.x); - size.y = ssize.y + vsize.y; - - if (ssize.y != 0) { - statuspanel->SetSize(0, 0, size.x, ssize.y); + // メインビューの方が小さければ両側に空き地を入れてセンタリングする。 + wxSize viewsize = mainview->GetSize(); + if (viewsize.x < client.x) { + int view_x = (client.x - viewsize.x) / 2; + spaceL->SetSize(0, statsize.y, view_x, viewsize.y); + spaceL->Show(); + mainview->SetSize(view_x, statsize.y, viewsize.x, viewsize.y); + int x = view_x + viewsize.x; + spaceR->SetSize(x, statsize.y, client.x - x, viewsize.y); + spaceR->Show(); + } else { + mainview->SetPosition(wxPoint(0, statsize.y)); + spaceL->Hide(); + spaceR->Hide(); } - mainview->SetSize(0, ssize.y, size.x, vsize.y); - SetClientSize(size); return true; } @@ -896,6 +1075,197 @@ WXMainFrame::OnMenuInputUI(wxUpdateUIEve } } +// メニューの「設定 > HostNet* > *」の選択肢イベント +void +WXMainFrame::OnMenuHostNet(wxCommandEvent& event) +{ + int id = event.GetId(); + uint unit; + uint choice; + + if (id <= ID_HOSTNET0_NONE) { + unit = 0; + choice = id; + } else { + unit = 1; + choice = id - ID_HOSTNET1_START + ID_HOSTNET0_START; + } + + // SLIRP モニタウィンドウはあれば閉じておく必要がある。 + if ((bool)windows[ID_MONITOR_SLIRP]) { + DoWindow(ID_MONITOR_SLIRP, false); + } + + // 設定を更新。 + std::string line = hostnet[unit]->GetConfigKey() + "-driver="; + switch (choice) { + case ID_HOSTNET0_USERMODE: line += "usermode"; break; + case ID_HOSTNET0_TAP: line += "tap"; break; + case ID_HOSTNET0_BPF: line += "bpf"; break; + case ID_HOSTNET0_AFPACKET: line += "afpacket"; break; + case ID_HOSTNET0_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + hostnet[unit]->NotifyReselectDriver(); +} + +// メニューの「設定 > HostNet* > *」の UI +void +WXMainFrame::OnMenuHostNetUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + uint unit; + + if (id <= ID_HOSTNET0_NONE) { + unit = 0; + } else { + unit = 1; + id = id - ID_HOSTNET1_START + ID_HOSTNET0_START; + } + + const std::string driver = hostnet[unit]->GetDriverName(); + uint selected; + if (driver == "usermode") { + selected = ID_HOSTNET0_USERMODE; + } else if (driver == "tap") { + selected = ID_HOSTNET0_TAP; + } else if (driver == "bpf") { + selected = ID_HOSTNET0_BPF; + } else if (driver == "afpacket") { + selected = ID_HOSTNET0_AFPACKET; + } else { + selected = ID_HOSTNET0_NONE; + } + + event.Check((id == selected)); +} + +// メニューの「設定 > HostCom* > *」の選択肢イベント +void +WXMainFrame::OnMenuHostCom(wxCommandEvent& event) +{ + int id = event.GetId(); + HostCOMDevice *host; + uint choice; + + if (id <= ID_HOSTCOM0_NONE) { + host = hostcom[0]; + choice = id; + } else if (id <= ID_HOSTCOM1_NONE) { + host = hostcom[1]; + choice = id - ID_HOSTCOM1_START + ID_HOSTCOM0_START; + } else if (id <= ID_HOSTCOM2_NONE) { + host = hostcom[2]; + choice = id - ID_HOSTCOM2_START + ID_HOSTCOM0_START; + } else { + host = hostcom_dbg; + choice = id - ID_HOSTCOM_DBG_START + ID_HOSTCOM0_START; + } + + // 設定を更新。 + std::string line = host->GetConfigKey() + "-driver="; + switch (choice) { + case ID_HOSTCOM0_TCP: line += "tcp"; break; + case ID_HOSTCOM0_STDIO: line += "stdio"; break; + case ID_HOSTCOM0_CONSOLE: line += "console"; break; + case ID_HOSTCOM0_NONE: line += "none"; break; + default: + assert(false); + } + gConfig->UpdateRunning(line); + + // ホストスレッドに通知。 + host->NotifyReselectDriver(); +} + +// メニューの「設定 > HostCom* > *」の UI +void +WXMainFrame::OnMenuHostComUI(wxUpdateUIEvent& event) +{ + int id = event.GetId(); + HostCOMDevice *host; + + if (id <= ID_HOSTCOM0_NONE) { + host = hostcom[0]; + } else if (id <= ID_HOSTCOM1_NONE) { + host = hostcom[1]; + id = id - ID_HOSTCOM1_START + ID_HOSTCOM0_START; + } else if (id <= ID_HOSTCOM2_NONE) { + host = hostcom[2]; + id = id - ID_HOSTCOM2_START + ID_HOSTCOM0_START; + } else { + host = hostcom_dbg; + id = id - ID_HOSTCOM_DBG_START + ID_HOSTCOM0_START; + } + + const std::string driver = host->GetDriverName(); + uint selected; + if (driver == "tcp") { + selected = ID_HOSTCOM0_TCP; + } else if (driver == "stdio") { + selected = ID_HOSTCOM0_STDIO; + } else if (driver == "console") { + selected = ID_HOSTCOM0_CONSOLE; + } else { + selected = ID_HOSTCOM0_NONE; + } + + event.Check((id == selected)); +} + +// hostnet ドライバ起動失敗のメッセージ。 +void +WXMainFrame::OnHostNetFailed(wxCommandEvent& event) +{ + wxString hostdev; + wxString errmsg; + uint n = event.GetInt(); + + hostdev.Printf("hostnet%u", n); + errmsg = hostnet[n]->GetErrmsg(); + HostDriverFailed(hostdev, errmsg); +} + +void +WXMainFrame::OnHostComFailed(wxCommandEvent& event) +{ + wxString hostdev; + wxString errmsg; + int n = event.GetInt(); + + if (n >= 0) { + hostdev.Printf("hostcom%u", n); + errmsg = hostcom[n]->GetErrmsg(); + } else { + hostdev = "debugger"; + errmsg = hostcom_dbg->GetErrmsg(); + } + HostDriverFailed(hostdev, errmsg); +} + +// ホストドライバ起動失敗のメッセージ。 +void +WXMainFrame::HostDriverFailed(const wxString& hostdev, const wxString& errmsg) +{ + wxString msg; + + msg = hostdev; + msg += ": "; + msg += _("Failed to switch the driver.\n" + "(Using 'none' instead)"); + if (!errmsg.empty()) { + msg += "\n\n"; + msg += _("Error message:"); + msg += ' '; + msg += errmsg; + } + ::wxMessageBox(msg); +} + // スケール一覧 /*static*/ std::vector WXMainFrame::view_scales { @@ -942,7 +1312,7 @@ WXMainFrame::OnMenuScale(wxCommandEvent& int idx = event.GetId() - ID_SCALE_START; mainview->DoResize(view_scales[idx]); // 再レイアウト - Layout(); + Fit(); } // メニューの「表示 > スケール > *」の共通 UI @@ -994,7 +1364,7 @@ WXMainFrame::OnMenuFontSize(wxCommandEve statuspanel->FontChanged(); // ステータスパネルの大きさが変わるので再レイアウト - Layout(); + Fit(); } } @@ -1074,7 +1444,7 @@ WXMainFrame::OnShowStatusPanel(wxCommand statuspanel->Show(enable); // 再レイアウト - Layout(); + Fit(); } // メニューの「表示 > ステータスパネルを表示」UI @@ -1273,13 +1643,6 @@ WXMainFrame::OnMouseMode(wxCommandEvent& // enable ならチェックを付けようとして呼ばれた bool enable = event.IsChecked(); - wxString new_title = frame_title; - if (enable) { - // メッセージを表示したい - new_title += " (CTRL + F12 to quit mouse mode)"; - } - SetTitle(new_title); - // マウスモードを設定 wxCommandEvent newev(NONO_EVT_MOUSEMODE, GetId()); newev.SetEventObject(this); @@ -1374,7 +1737,7 @@ WXMainFrame::DoWindow(int id, bool enabl } case ID_MONITOR_BREAKPOINT: - SetMonitor(id, _("Breakpoint")); + SetMonitor(id, _("Breakpoints")); break; case ID_MONITOR_BT45x: @@ -1397,6 +1760,8 @@ WXMainFrame::DoWindow(int id, bool enabl } else { name += _("(Inst)"); } + name += ' '; + name += _("Registers"); SetMonitor(id, name); break; } @@ -1413,30 +1778,31 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, "FDC (uPD72065B)"); break; - case ID_MONITOR_HOSTCOM: - SetMonitor(id, _("Host Serial Port")); + case ID_MONITOR_HOSTCOM0: + case ID_MONITOR_HOSTCOM1: + case ID_MONITOR_HOSTCOM2: + { + uint n = id - ID_MONITOR_HOSTCOM0; + SetMonitor(id, GetHostComLabel(n)); break; + } case ID_MONITOR_HOSTNET0: case ID_MONITOR_HOSTNET1: { - wxString name = _("Host Network"); - if (gMainApp.IsX68030()) { - uint n = id - ID_MONITOR_HOSTNET0; - name += string_format(" #%u", n); - } - SetMonitor(id, name); + uint n = id - ID_MONITOR_HOSTNET0; + SetMonitor(id, GetHostNetLabel(n)); break; } case ID_MONITOR_INTERRUPT: { wxString name; - if (gMainApp.Has(VMCap::M88K)) { - // 実際はほぼシステムコントローラなのでややこしい。 - name = "MPU " + _("Interrupt"); + if (gMainApp.Has(VMCap::M68K)) { + name = MPUName() + " " + _("Interrupts"); } else { - name = MPUName() + " " + _("Interrupt"); + // 実際はほぼシステムコントローラなのでややこしい。 + name = "MPU " + _("Interrupts"); } SetMonitor(id, name); break; @@ -1496,11 +1862,11 @@ WXMainFrame::DoWindow(int id, bool enabl break; case ID_MONITOR_MPUCACHE: - SetMonitor(id, MPUName() + " " + _("Cache")); + SetMonitor(id, MPUName() + " " + _("Caches")); break; case ID_MONITOR_MPUREG: - SetMonitor(id, MPUName() + " " + _("Register")); + SetMonitor(id, MPUName() + " " + _("Registers")); break; case ID_MONITOR_NEREID: @@ -1539,7 +1905,7 @@ WXMainFrame::DoWindow(int id, bool enabl case ID_MONITOR_RTL8019AS1: { uint n = id - ID_MONITOR_RTL8019AS0; - wxString name = string_format("Nereid (RTL8019AS) #%u", n); + wxString name = string_format("Nereid#%u (RTL8019AS)", n); SetMonitor(id, name); break; } @@ -1605,12 +1971,16 @@ WXMainFrame::DoWindow(int id, bool enabl SetMonitor(id, _("Host Information")); break; + case ID_MONITOR_XPASCI: + SetMonitor(id, "HD647180 ASCI"); + break; + case ID_MONITOR_XPREG: - SetMonitor(id, "HD647180 " + _("Register")); + SetMonitor(id, "HD647180 " + _("Registers")); break; case ID_MONITOR_XPINTR: - SetMonitor(id, "HD647180 " + _("Interrupt")); + SetMonitor(id, "HD647180 " + _("Interrupts")); break; case ID_MONITOR_XPIO: @@ -1796,6 +2166,13 @@ WXMainFrame::OnWindowUI(wxUpdateUIEvent& // ウィンドウが存在していればチェックを表示 event.Check((bool)windows[id]); + // SLIRP モニタだけ無効状態がある。 +#if defined(HAVE_HOSTNET_SLIRP) + if (__predict_false(id == ID_MONITOR_SLIRP)) { + event.Enable(NetDriverSlirp::IsOccupied()); + } +#endif + if (IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id)) { // メニューに現在のアドレスを載せる // (ウィンドウの生存期間外にも呼ばれることに注意) @@ -1907,6 +2284,36 @@ WXMainFrame::OnHaltNotify(wxCommandEvent wxICON_EXCLAMATION); } +// HostNet に対する表示用テキストを返す。 +wxString +WXMainFrame::GetHostNetLabel(uint n) const +{ + return wxString(string_format("HostNet%u: ", n) + + hostnet[n]->GetPortName()); +} + +// HostCOM に対する表示用テキストを返す。 +// デバッガ用は呼び出し側で処理すること。 +wxString +WXMainFrame::GetHostComLabel(uint n) const +{ + assert((int)n >= 0); + return wxString(string_format("HostCom%u: ", n) + + hostcom[n]->GetPortName()); +} + +// メインウィンドウのタイトルを (mousemode によって) 変更する。 +void +WXMainFrame::SetMyTitle(bool mousemode) +{ + wxString new_title = frame_title; + if (mousemode) { + // メッセージを表示したい + new_title += " (CTRL + F12 to quit mouse mode)"; + } + SetTitle(new_title); +} + // 起動時にオープンするサブウィンドウ (-M オプション) /*static*/ std::array WXMainFrame::subwindow_start;