Annotation of nono/wx/wxapp.cpp, revision 1.1.1.13

1.1       root        1: //
                      2: // nono
1.1.1.3   root        3: // Copyright (C) 2020 nono project
                      4: // Licensed under nono-license.txt
1.1       root        5: //
                      6: 
1.1.1.11  root        7: //
                      8: // wx アプリケーションのエントリポイント
                      9: //
                     10: 
                     11: #include "fontmanager.h"
                     12: #include "wxlogsetting.h"
1.1       root       13: #include "wxmainframe.h"
                     14: #include "wxmainview.h"
1.1.1.11  root       15: #include "wxuimessage.h"
1.1.1.4   root       16: #include "wxversion.h"
1.1.1.13! root       17: #include "config.h"
1.1       root       18: #include "mainapp.h"
1.1.1.13! root       19: #include "memdump.h"
1.1.1.8   root       20: #include <algorithm>
1.1.1.3   root       21: #include <wx/intl.h>
1.1       root       22: 
1.1.1.8   root       23: class WXApp : public wxApp
1.1       root       24: {
1.1.1.6   root       25:        using inherited = wxApp;
1.1       root       26:  public:
1.1.1.11  root       27:        ~WXApp() override;
1.1.1.13! root       28:        bool OnInit() override;
1.1.1.6   root       29:        int OnRun() override;
1.1       root       30:  private:
                     31:        bool ParseMonitors(const wxString& str);
1.1.1.13! root       32:        bool ParseMemdumpValue(int id, const std::string&, const std::string&);
1.1.1.8   root       33:        void ShowMonitorsName();
1.1       root       34:        int SearchMonitorName(const char *name);
1.1.1.13! root       35:        int FindAvailable(const std::vector<int>& candidates,
        !            36:                const std::string& name, int basenum, int count) const;
1.1.1.3   root       37: 
                     38:        wxLocale locale;
1.1.1.11  root       39: 
                     40:        std::unique_ptr<FontManager> pFontManager {};
                     41:        std::unique_ptr<HostInfoMonitor> pHostInfo {};
1.1       root       42: };
                     43: 
1.1.1.3   root       44: // IMPLEMENT_APP() は闇マクロすぎて clang のちからには耐えられない
1.1.1.11  root       45: PRAGMA_PUSH_WARNINGS
1.1       root       46: IMPLEMENT_APP(WXApp)
1.1.1.11  root       47: PRAGMA_POP_WARNINGS
                     48: 
                     49: WXApp::~WXApp()
                     50: {
                     51:        // 開発用
                     52:        WXUIMessage::AssertAllDisconnected();
                     53: }
1.1       root       54: 
                     55: bool
                     56: WXApp::OnInit()
                     57: {
1.1.1.6   root       58:        return true;
                     59: }
                     60: 
                     61: int
                     62: WXApp::OnRun()
                     63: {
1.1.1.5   root       64:        int rv;
                     65: 
1.1.1.7   root       66:        rv = gMainApp.Init1(false, argc, argv);
1.1.1.5   root       67:        if (rv != MainApp::PASS) {
1.1.1.6   root       68:                return rv;
1.1       root       69:        }
                     70: 
1.1.1.3   root       71:        // 環境変数 $NONO_BUILD_HOME が定義されていればカタログ検索パスに
                     72:        // $NONO_BUILD_HOME/po を追加する (システムパスより前に挿入される)。
                     73:        // カタログ開発時にワークツリーにあるカタログを見るため。
1.1.1.13! root       74:        locale.Init(wxLANGUAGE_DEFAULT, wxLOCALE_DONT_LOAD_DEFAULT);
1.1.1.3   root       75:        const char *build_home = getenv("NONO_BUILD_HOME");
                     76:        if (build_home) {
                     77:                wxString path(build_home);
                     78:                path += "/po";
                     79:                wxLocale::AddCatalogLookupPathPrefix(path);
                     80:        }
                     81:        locale.AddCatalog("nono");
                     82: 
1.1.1.13! root       83:        // テキスト系コントロールのフォントサイズ。
        !            84:        // 紛らわしいが設定の monitor-fontsize は 12, 16 とかいう値。
1.1.1.11  root       85:        // FontManager::fontid は enum 値。
1.1.1.13! root       86:        const ConfigItem& item_fontsize = gConfig->Find("monitor-fontsize");
        !            87:        int fontsize = item_fontsize.AsInt();
1.1.1.4   root       88:        FontId fontid;
1.1.1.13! root       89:        switch (fontsize) {
1.1.1.2   root       90:         case 12:
1.1.1.4   root       91:                fontid = FontId::_6x12;
1.1.1.2   root       92:                break;
                     93:         case 16:
1.1.1.4   root       94:                fontid = FontId::_8x16;
1.1.1.2   root       95:                break;
1.1.1.13! root       96:         case 24:
        !            97:                fontid = FontId::_12x24;
        !            98:                break;
1.1.1.2   root       99:         default:
1.1.1.13! root      100:                item_fontsize.Err("Must be either 12, 16 or 24");
1.1.1.7   root      101:                return EXIT_FAILURE;
1.1       root      102:        }
1.1.1.11  root      103:        pFontManager.reset(new FontManager());
                    104:        gFontManager = pFontManager.get();
                    105:        gFontManager->SetFont(fontid);
                    106: 
                    107:        // ホスト情報用のモニタ (どこでやるのがいいか)
                    108:        pHostInfo.reset(new HostInfoMonitor());
                    109:        gHostInfo = pHostInfo.get();
1.1       root      110: 
1.1.1.11  root      111:        // 手順 4. (vm/device.h)
1.1.1.8   root      112:        // これ以降モニタの登録をしてはいけない。
1.1.1.11  root      113:        gMonitorManager->Fix();
1.1.1.8   root      114: 
1.1       root      115:        // -M 起動時に表示するモニタ
1.1.1.2   root      116:        if (!gMainApp.monitor_opt.empty()) {
                    117:                if (!ParseMonitors(gMainApp.monitor_opt)) {
1.1.1.7   root      118:                        return EXIT_FAILURE;
1.1       root      119:                }
                    120:        }
                    121: 
1.1.1.13! root      122:        // メインスクリーン倍率
        !           123:        const ConfigItem& item_scale = gConfig->Find("mainview-scale");
        !           124:        double scale;
        !           125:        if (item_scale.TryDouble(&scale) == false) {
        !           126:                item_scale.Err();
        !           127:                return EXIT_FAILURE;
        !           128:        }
        !           129:        // 制限は適当
        !           130:        if (scale <= 0 || scale >= 10) {
        !           131:                item_scale.Err();
        !           132:                return EXIT_FAILURE;
        !           133:        }
        !           134:        WXMainView::screen_scale = scale;
        !           135: 
        !           136:        // モニター更新間隔
        !           137:        const ConfigItem& item_rate = gConfig->Find("monitor-rate");
        !           138:        int rate = item_rate.AsInt();
        !           139:        if (rate < 1 || rate > 60) {
        !           140:                item_rate.Err();
        !           141:                return EXIT_FAILURE;
        !           142:        }
        !           143:        WXMainFrame::SetMonitorRate(rate);
1.1       root      144: 
1.1.1.7   root      145:        // 引数処理が終わったので、スレッド作成を伴う初期化。
                    146:        if (!gMainApp.Init2()) {
                    147:                return EXIT_FAILURE;
                    148:        }
                    149: 
1.1.1.2   root      150:        // メインウィンドウ
1.1.1.13! root      151:        auto mainframe = new WXMainFrame(NULL);
        !           152:        mainframe->Show(true);
        !           153:        SetTopWindow(mainframe);
1.1.1.6   root      154: 
1.1.1.10  root      155:        // 設定反映などの初期化
1.1.1.13! root      156:        if (!mainframe->Init()) {
1.1.1.10  root      157:                return EXIT_FAILURE;
                    158:        }
                    159: 
1.1.1.6   root      160:        return inherited::OnRun();
1.1       root      161: }
                    162: 
                    163: // -M オプションの解析。書式は
1.1.1.8   root      164: //  -M <arg>[,<arg>[,...]]
                    165: // <arg> のどれかが "help" なら有効な名前を列挙して終了。
                    166: // <arg> は通常モニタ名(サブウィンドウ名)のみだが
                    167: // memdump* の場合のみ <name>=<hexaddr> 形式を受け付ける。
                    168: // 継続する場合は true、しない場合は false を返す。
1.1       root      169: bool
                    170: WXApp::ParseMonitors(const wxString& str)
                    171: {
1.1.1.8   root      172:        std::vector<std::string> args = string_split(str, ',');
1.1       root      173: 
1.1.1.8   root      174:        // "help" があればヘルプを表示して終了
                    175:        for (const auto& arg : args) {
                    176:                if (arg == "help") {
                    177:                        ShowMonitorsName();
                    178:                        return false;
1.1       root      179:                }
                    180:        }
                    181: 
1.1.1.8   root      182:        // 一致するモニタ(ウィンドウ)の開始フラグを立てる
                    183:        for (const auto& arg : args) {
                    184:                std::string name;
                    185:                std::string value;
                    186: 
                    187:                auto pos = arg.find('=');
                    188:                if (pos != std::string::npos) {
                    189:                        name = arg.substr(0, pos);
                    190:                        value = arg.substr(++pos);
                    191:                } else {
                    192:                        name = arg;
1.1.1.3   root      193:                }
1.1.1.8   root      194: 
                    195:                // この名前のウィンドウを探して start フラグを立てる
                    196:                int id = SearchMonitorName(name.c_str());
                    197:                if (id < 0) {
1.1       root      198:                        return false;
                    199:                }
1.1.1.8   root      200:                WXMainFrame::subwindow_start[id] = true;
                    201: 
                    202:                // 値付き memdump の処理
1.1.1.13! root      203:                if ((IS_MONITOR_MEMDUMP(id) || IS_MONITOR_XPMEMDUMP(id))
        !           204:                                && value.empty() == false)
        !           205:                {
        !           206:                        if (ParseMemdumpValue(id, name, value) == false) {
        !           207:                                return false;
        !           208:                        }
        !           209:                }
        !           210:        }
        !           211:        return true;
        !           212: }
        !           213: 
        !           214: // -Mmemdump= の続きの文字列 value を解析してセットする。
        !           215: // 書式は <hex-address>[.<fmt>]
        !           216: // fmt は B/W/L と M(MMU)、I(dIsasm)、Z(XPdisasm)
        !           217: bool
        !           218: WXApp::ParseMemdumpValue(int id,
        !           219:        const std::string& name, const std::string& value)
        !           220: {
        !           221:        auto mon = gMonitorManager->Get(id);
        !           222:        auto memdump = dynamic_cast<Memdump *>(mon.obj);
        !           223:        assert(memdump);
        !           224: 
        !           225:        errno = 0;
        !           226:        char *end;
        !           227:        unsigned long u = strtoul(value.c_str(), &end, 16);
        !           228:        // これが呼ばれた時点で value は空ではないはず
        !           229:        if (errno == ERANGE || u > 0xffffffff) {
        !           230:                errno = ERANGE;
        !           231:                warn("-M %s=%s", name.c_str(), value.c_str());
        !           232:                return false;
        !           233:        }
        !           234:        // アドレスを設定
        !           235:        memdump->SetAddr((uint32)u);
        !           236: 
        !           237:        // さらに後ろがあれば表示形式指定。
        !           238:        if (*end != '\0') {
        !           239:                if (*end++ != '.') {
        !           240:                        goto usage;
        !           241:                }
        !           242: 
        !           243:                if (end[1] != '\0') {
        !           244:                        goto usage;
        !           245:                }
        !           246: 
        !           247:                Memdump::Format fmt;
        !           248:                switch (std::toupper((int)*end)) {
        !           249:                 case 'B':      fmt = Memdump::Byte;    break;
        !           250:                 case '\0':
        !           251:                 case 'W':      fmt = Memdump::Word;    break;
        !           252:                 case 'L':      fmt = Memdump::Long;    break;
        !           253:                 case 'M':
        !           254:                        if (gMainApp.Has(VMCap::M88K)) {
        !           255:                                fmt = Memdump::M88200Page;
        !           256:                        } else {
        !           257:                                // ロングは指定できないけど使われてないので放置
        !           258:                                fmt = Memdump::M68030PageShort;
1.1.1.8   root      259:                        }
1.1.1.13! root      260:                        break;
        !           261:                 case 'I':
        !           262:                        if (gMainApp.Has(VMCap::M88K)) {
        !           263:                                fmt = Memdump::M88100Disasm;
        !           264:                        } else {
        !           265:                                fmt = Memdump::M68030Disasm;
1.1.1.8   root      266:                        }
1.1.1.13! root      267:                        break;
        !           268:                 case 'Z':
        !           269:                        fmt = Memdump::HD64180Disasm;
        !           270:                        break;
        !           271:                 default:
        !           272:                 usage:
        !           273:                        warnx("-M %s=%s: syntax error; syntax is \"<hex-addr>[.<BWLMDX>]\"",
        !           274:                                name.c_str(), value.c_str());
        !           275:                        return false;
1.1.1.8   root      276:                }
1.1.1.13! root      277: 
        !           278:                // 表示形式を設定
        !           279:                memdump->SetFormat(fmt);
1.1       root      280:        }
1.1.1.13! root      281: 
1.1       root      282:        return true;
                    283: }
                    284: 
1.1.1.8   root      285: // モニタ名の一覧を表示する
                    286: void
                    287: WXApp::ShowMonitorsName()
                    288: {
                    289:        std::vector<int> list;
                    290: 
                    291:        // モニターは登録されていれば列挙
                    292:        // (登録されているものを全部列挙ではないことに注意)
                    293:        for (int id = ID_MONITOR_START; id <= ID_MONITOR_END; id++) {
1.1.1.11  root      294:                if (gMonitorManager->Find(id)) {
1.1.1.8   root      295:                        list.push_back(id);
                    296:                }
                    297:        }
                    298:        // サブウィンドウは機種情報から判断
                    299:        for (int id = ID_SUBWIN_START; id <= ID_SUBWIN_END; id++) {
1.1.1.12  root      300:                VMCap vmcap = gMonitorManager->GetVMCap(id);
                    301:                if (gMainApp.Has(vmcap)) {
1.1.1.8   root      302:                        list.push_back(id);
                    303:                }
                    304:        }
                    305: 
                    306:        // 一覧を表示
                    307:        std::string msg = MonitorManager::MakeListString(list);
                    308:        printf("%s", msg.c_str());
                    309: }
                    310: 
                    311: // モニタ名 name を検索し、一つに確定すればその id を返す。
                    312: // 確定しない、あるいは一致しない場合はエラーメッセージを表示し -1 を返す。
                    313: //
                    314: // "memdump" (数字なし) は空いてる memdump<N> を順に使用する。
                    315: // ただし今の所この処理は1パスで前から順に処理しているだけなので、
                    316: // "memdump0,memdump" は指定可能だが(2つ目が memdump1 になる)、
                    317: // "memdump,memdump0" は memdump0 を2回指定したことになる。
1.1       root      318: int
                    319: WXApp::SearchMonitorName(const char *name)
                    320: {
1.1.1.8   root      321:        std::vector<int> candidates;
                    322:        std::vector<std::string> cand_names;
                    323: 
                    324:        for (int id = ID_MONITOR_START; id <= ID_SUBWIN_END; id++) {
                    325:                if (id < ID_SUBWIN_START) {
                    326:                        // モニターは登録されていなければ除外する
1.1.1.11  root      327:                        if (gMonitorManager->Find(id) == NULL) {
1.1.1.8   root      328:                                continue;
                    329:                        }
                    330:                } else {
                    331:                        // サブウィンドウは該当機種でなければ除外する
1.1.1.12  root      332:                        VMCap vmcap = gMonitorManager->GetVMCap(id);
                    333:                        if (gMainApp.Has(vmcap) == false) {
1.1.1.8   root      334:                                continue;
                    335:                        }
                    336:                }
                    337: 
1.1.1.11  root      338:                const auto& aliases = gMonitorManager->GetAliases(id);
1.1.1.8   root      339: 
                    340:                bool matched = false;
                    341:                for (const auto& alias : aliases) {
                    342:                        // 全文一致したら確定
                    343:                        // ("lunafb" と "lunafb0" みたいなのがあるため)
                    344:                        if (alias == name) {
                    345:                                return id;
                    346:                        }
                    347: 
                    348:                        // 部分一致したら名前はすべて覚えておく
                    349:                        if (starts_with_ignorecase(alias, name)) {
                    350:                                cand_names.push_back(alias);
                    351:                                matched = true;
                    352:                        }
                    353:                }
                    354:                // 同じオブジェクトで別名が複数回部分一致しても、1回として数える
                    355:                if (matched) {
                    356:                        candidates.push_back(id);
                    357:                }
                    358:        }
                    359: 
                    360:        if (candidates.empty()) {
                    361:                // 一致しない
                    362:                warnx("Unknown window name \"%s\"", name);
                    363:                return -1;
                    364:        } else if (candidates.size() == 1) {
                    365:                // 部分一致したのが1つだけなら確定
                    366:                return candidates[0];
                    367:        } else {
                    368:                // 候補が複数あった
1.1.1.13! root      369:                int id;
1.1.1.8   root      370: 
1.1.1.13! root      371:                // "memdump" を空いてる "memdump*" に割り当てる
        !           372:                id = FindAvailable(candidates, "memdump",
        !           373:                        ID_MONITOR_MEMDUMP0, MAX_MEMDUMP_MONITOR);
        !           374:                if (id != 0) {
        !           375:                        return id;
        !           376:                }
        !           377: 
        !           378:                // "xpmemdump" を空いてる "xpmemdump*" に割り当てる
        !           379:                id = FindAvailable(candidates, "xpmemdump",
        !           380:                        ID_MONITOR_XPMEMDUMP0, MAX_XPMEMDUMP_MONITOR);
        !           381:                if (id != 0) {
        !           382:                        return id;
1.1.1.8   root      383:                }
                    384: 
                    385:                // そうでなければ、候補を表示
                    386:                std::string candstr;
                    387:                for (const auto& cname : cand_names) {
                    388:                        candstr += ' ';
                    389:                        candstr += cname;
1.1       root      390:                }
1.1.1.8   root      391:                warnx("Ambiguous window name \"%s\": candidates are%s",
                    392:                        name, candstr.c_str());
                    393:                return -1;
1.1       root      394:        }
                    395: }
1.1.1.13! root      396: 
        !           397: // candidates (候補の一覧) がすべて basenum .. count 内に入っていれば、
        !           398: // その中の空きウィンドウ ID を返す。
        !           399: // 空きがなければエラーメッセージを表示して - 1 を返す。
        !           400: // candidates の中に basenum .. count 内に入っていないものがあれば 0 を返す。
        !           401: // 今の所ここでターゲットにしている人たちに ID=0 はいないので。
        !           402: // start は ID_MONITOR_*0、count は MAX_*_MONITOR のほうで、
        !           403: // 最初と最後の ID ではないので注意。
        !           404: int
        !           405: WXApp::FindAvailable(const std::vector<int>& candidates,
        !           406:        const std::string& name, int start, int count) const
        !           407: {
        !           408:        // candidates がすべてこの start..end に入っているか
        !           409:        bool all = std::all_of(candidates.begin(), candidates.end(),
        !           410:                [&](int id) { return (start <= id && id < start + count); }
        !           411:        );
        !           412: 
        !           413:        if (all) {
        !           414:                // この時点で空いてるものを返す。
        !           415:                for (int i = 0; i < count; i++) {
        !           416:                        int id = start + i;
        !           417:                        if (WXMainFrame::subwindow_start[id] == false) {
        !           418:                                return id;
        !           419:                        }
        !           420:                }
        !           421:                // 空きがなければエラー
        !           422:                warnx("No more %s windows available", name.c_str());
        !           423:                return -1;
        !           424:        }
        !           425: 
        !           426:        // 候補が他にもあった
        !           427:        return 0;
        !           428: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.