// window_origin — pure implementation. See window_origin.h. #include "core/ui/window_origin.h" #include namespace reasampler::ui { namespace { // Case-folded (ASCII only — Windows' own directory names are ASCII), separator-unified, with the // "\\?\" long-path prefix GetModuleFileName may report dropped, so the same directory compares // equal however each API chose to spell it. std::string normalizePath(const std::string& p) { std::string s = p.rfind("\\\\?\\", 0) == 0 ? p.substr(4) : p; for (char& c : s) { if (c == '/') c = '\\'; else if (c >= 'A' && c <= 'Z') c = static_cast(c - 'A' + 'a'); } while (!s.empty() && s.back() == '\\') s.pop_back(); return s; } // Directory containment, not string prefix: C:\Windows must not claim C:\WindowsApps. bool isBeneath(const std::string& path, const std::string& dir) { const std::string p = normalizePath(path); const std::string d = normalizePath(dir); return !d.empty() && p.size() > d.size() && p.compare(0, d.size(), d) == 0 && p[d.size()] == '\\'; } } // namespace WindowCode classifyWindowCode(const WindowFacts& facts, const std::string& systemRoot) { // Another process's procedure address means nothing in ours; the process boundary is itself // the proof. Inside an FX window that is the bridged plugin's editor. if (facts.otherProcess) return WindowCode::Plugin; if (!facts.procResolved) return WindowCode::Unknown; if (facts.hostModule) return WindowCode::Host; if (normalizePath(systemRoot).empty()) return WindowCode::Unknown; return isBeneath(facts.modulePath, systemRoot) ? WindowCode::System : WindowCode::Plugin; } bool isPluginEditorChain(const std::vector& chain) { return std::find(chain.begin(), chain.end(), WindowCode::Plugin) != chain.end(); } } // namespace reasampler::ui