Add platform abstraction & cross-platform ports
Introduce a cross-platform platform layer and port scaffolding for macOS and Linux. CMakeLists.txt refactored to select platform sources, set executable type per OS, and use CEF helper macros for runtime deployment. Add platform/types.h, startup/paths/browser_host APIs and implementations for Windows, macOS, and Linux (many are stubs for mac/linux). Refactor app entry and lifetime to use nebula::platform::AppStartup (app/main, run.{h,cpp}), move window/browser host logic into platform/browser_host.*, and update NebulaController to use platform APIs (native handles, sizing, visibility, cache-busting token, etc.). Add README and detailed docs/cross-platform.md describing build layout and porting status.
This commit is contained in:
+27
-59
@@ -1,6 +1,6 @@
|
||||
#include "ui/paths.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "platform/paths_platform.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
@@ -10,40 +10,25 @@ namespace nebula::ui {
|
||||
namespace {
|
||||
|
||||
constexpr std::string_view kNebulaScheme = "nebula://";
|
||||
constexpr std::wstring_view kInternalFallbackPage = L"404.html";
|
||||
constexpr std::string_view kInternalFallbackPage = "404.html";
|
||||
|
||||
struct InternalPage {
|
||||
std::string_view slug;
|
||||
std::wstring_view file_name;
|
||||
std::string_view file_name;
|
||||
};
|
||||
|
||||
constexpr InternalPage kInternalPages[] = {
|
||||
{"home", L"home.html"},
|
||||
{"settings", L"settings.html"},
|
||||
{"downloads", L"downloads.html"},
|
||||
{"bigpicture", L"bigpicture.html"},
|
||||
{"big-picture", L"bigpicture.html"},
|
||||
{"gpu-diagnostics", L"gpu-diagnostics.html"},
|
||||
{"setup", L"setup.html"},
|
||||
{"404", L"404.html"},
|
||||
{"insecure", L"insecure.html"},
|
||||
{"home", "home.html"},
|
||||
{"settings", "settings.html"},
|
||||
{"downloads", "downloads.html"},
|
||||
{"bigpicture", "bigpicture.html"},
|
||||
{"big-picture", "bigpicture.html"},
|
||||
{"gpu-diagnostics", "gpu-diagnostics.html"},
|
||||
{"setup", "setup.html"},
|
||||
{"404", "404.html"},
|
||||
{"insecure", "insecure.html"},
|
||||
};
|
||||
|
||||
std::string WideToUtf8(const std::wstring& value) {
|
||||
if (value.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const int size = WideCharToMultiByte(
|
||||
CP_UTF8, 0, value.data(), static_cast<int>(value.size()),
|
||||
nullptr, 0, nullptr, nullptr);
|
||||
std::string result(size, '\0');
|
||||
WideCharToMultiByte(
|
||||
CP_UTF8, 0, value.data(), static_cast<int>(value.size()),
|
||||
result.data(), size, nullptr, nullptr);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string GetUrlWithoutDecoration(std::string url) {
|
||||
const size_t split = url.find_first_of("?#");
|
||||
if (split != std::string::npos) {
|
||||
@@ -64,8 +49,8 @@ std::string ToLowerAscii(std::string value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
std::string PageFileUrl(std::wstring_view page_name) {
|
||||
const auto path = GetUiPagePath(std::wstring(page_name));
|
||||
std::string PageFileUrl(std::string_view page_name) {
|
||||
const auto path = GetUiPagePath(std::string(page_name));
|
||||
return path.empty() ? std::string{} : FilePathToUrl(path);
|
||||
}
|
||||
|
||||
@@ -127,36 +112,19 @@ const InternalPage* FindInternalPageByFileUrl(const std::string& url) {
|
||||
} // namespace
|
||||
|
||||
std::filesystem::path GetExecutableDirectory() {
|
||||
wchar_t exe_path[MAX_PATH] = {};
|
||||
const DWORD length = GetModuleFileNameW(nullptr, exe_path, MAX_PATH);
|
||||
if (length == 0 || length == MAX_PATH) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return std::filesystem::path(exe_path).parent_path();
|
||||
return nebula::platform::ExecutableDirectory();
|
||||
}
|
||||
|
||||
std::filesystem::path GetUserDataDirectory() {
|
||||
std::filesystem::path root;
|
||||
|
||||
wchar_t buffer[MAX_PATH] = {};
|
||||
// Prefer %LOCALAPPDATA% so the profile follows Chromium conventions and
|
||||
// survives executable relocation.
|
||||
const DWORD length =
|
||||
GetEnvironmentVariableW(L"LOCALAPPDATA", buffer, MAX_PATH);
|
||||
if (length > 0 && length < MAX_PATH) {
|
||||
root = std::filesystem::path(buffer);
|
||||
} else {
|
||||
// Fall back to a directory next to the executable so a portable
|
||||
// install still gets a writable profile.
|
||||
auto root = nebula::platform::DefaultUserDataRoot();
|
||||
if (root.empty()) {
|
||||
root = GetExecutableDirectory();
|
||||
}
|
||||
|
||||
if (root.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::filesystem::path user_data = root / L"Nebula" / L"User Data";
|
||||
std::filesystem::path user_data = root / "Nebula" / "User Data";
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(user_data, ec);
|
||||
return user_data;
|
||||
@@ -168,7 +136,7 @@ std::filesystem::path GetCacheDirectory() {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::filesystem::path cache = user_data / L"Cache";
|
||||
std::filesystem::path cache = user_data / "Cache";
|
||||
std::error_code ec;
|
||||
std::filesystem::create_directories(cache, ec);
|
||||
return cache;
|
||||
@@ -176,20 +144,20 @@ std::filesystem::path GetCacheDirectory() {
|
||||
|
||||
std::filesystem::path GetSessionStatePath() {
|
||||
auto user_data = GetUserDataDirectory();
|
||||
return user_data.empty() ? std::filesystem::path{} : user_data / L"session_state.json";
|
||||
return user_data.empty() ? std::filesystem::path{} : user_data / "session_state.json";
|
||||
}
|
||||
|
||||
std::filesystem::path GetUiPagePath(const std::wstring& page_name) {
|
||||
std::filesystem::path GetUiPagePath(const std::string& page_name) {
|
||||
const auto exe_dir = GetExecutableDirectory();
|
||||
if (exe_dir.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return exe_dir / L"ui" / L"pages" / page_name;
|
||||
return exe_dir / "ui" / "pages" / page_name;
|
||||
}
|
||||
|
||||
std::string FilePathToUrl(std::filesystem::path path) {
|
||||
std::string value = WideToUtf8(path.wstring());
|
||||
std::string value = nebula::platform::PathToUtf8(path);
|
||||
for (char& ch : value) {
|
||||
if (ch == '\\') {
|
||||
ch = '/';
|
||||
@@ -205,8 +173,8 @@ std::string FilePathToUrl(std::filesystem::path path) {
|
||||
}
|
||||
|
||||
std::string GetChromeUrl() {
|
||||
const auto path = GetUiPagePath(L"chrome.html");
|
||||
const std::string fallback = PageFileUrl(L"home.html");
|
||||
const auto path = GetUiPagePath("chrome.html");
|
||||
const std::string fallback = PageFileUrl("home.html");
|
||||
return path.empty() ? (fallback.empty() ? "https://www.google.com" : fallback) : FilePathToUrl(path);
|
||||
}
|
||||
|
||||
@@ -231,8 +199,8 @@ std::string GetGpuDiagnosticsUrl() {
|
||||
}
|
||||
|
||||
std::string GetMenuPopupUrl() {
|
||||
const auto path = GetUiPagePath(L"menu-popup.html");
|
||||
const std::string fallback = PageFileUrl(L"home.html");
|
||||
const auto path = GetUiPagePath("menu-popup.html");
|
||||
const std::string fallback = PageFileUrl("home.html");
|
||||
return path.empty() ? (fallback.empty() ? "https://www.google.com" : fallback) : FilePathToUrl(path);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user