2026-02-02 12:24:50 -08:00
|
|
|
#include "core/application.hpp"
|
|
|
|
|
#include "core/logger.hpp"
|
|
|
|
|
#include <exception>
|
2026-02-07 17:59:40 -08:00
|
|
|
#include <csignal>
|
2026-02-22 06:32:49 -08:00
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cctype>
|
|
|
|
|
#include <string>
|
2026-02-07 17:59:40 -08:00
|
|
|
#include <SDL2/SDL.h>
|
2026-02-18 17:38:08 -08:00
|
|
|
#ifdef __linux__
|
2026-02-07 17:59:40 -08:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
|
|
2026-02-07 18:33:14 -08:00
|
|
|
// Keep a persistent X11 connection for emergency mouse release in signal handlers.
|
|
|
|
|
// XOpenDisplay inside a signal handler is unreliable, so we open it once at startup.
|
|
|
|
|
static Display* g_emergencyDisplay = nullptr;
|
|
|
|
|
|
2026-02-07 17:59:40 -08:00
|
|
|
static void releaseMouseGrab() {
|
2026-02-07 18:33:14 -08:00
|
|
|
if (g_emergencyDisplay) {
|
|
|
|
|
XUngrabPointer(g_emergencyDisplay, CurrentTime);
|
|
|
|
|
XUngrabKeyboard(g_emergencyDisplay, CurrentTime);
|
|
|
|
|
XFlush(g_emergencyDisplay);
|
2026-02-07 17:59:40 -08:00
|
|
|
}
|
|
|
|
|
}
|
2026-02-18 17:38:08 -08:00
|
|
|
#else
|
|
|
|
|
static void releaseMouseGrab() {}
|
|
|
|
|
#endif
|
2026-02-07 17:59:40 -08:00
|
|
|
|
|
|
|
|
static void crashHandler(int sig) {
|
|
|
|
|
releaseMouseGrab();
|
|
|
|
|
std::signal(sig, SIG_DFL);
|
|
|
|
|
std::raise(sig);
|
|
|
|
|
}
|
2026-02-02 12:24:50 -08:00
|
|
|
|
2026-02-22 06:32:49 -08:00
|
|
|
static wowee::core::LogLevel readLogLevelFromEnv() {
|
|
|
|
|
const char* raw = std::getenv("WOWEE_LOG_LEVEL");
|
|
|
|
|
if (!raw || !*raw) return wowee::core::LogLevel::WARNING;
|
|
|
|
|
std::string level(raw);
|
|
|
|
|
for (char& c : level) c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
|
|
|
|
|
if (level == "debug") return wowee::core::LogLevel::DEBUG;
|
|
|
|
|
if (level == "info") return wowee::core::LogLevel::INFO;
|
|
|
|
|
if (level == "warn" || level == "warning") return wowee::core::LogLevel::WARNING;
|
2026-02-25 11:14:53 -08:00
|
|
|
if (level == "error") return wowee::core::kLogLevelError;
|
2026-02-22 06:32:49 -08:00
|
|
|
if (level == "fatal") return wowee::core::LogLevel::FATAL;
|
|
|
|
|
return wowee::core::LogLevel::WARNING;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-07 11:43:37 -08:00
|
|
|
int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) {
|
2026-02-18 17:38:08 -08:00
|
|
|
#ifdef __linux__
|
2026-02-07 18:33:14 -08:00
|
|
|
g_emergencyDisplay = XOpenDisplay(nullptr);
|
2026-02-18 17:38:08 -08:00
|
|
|
#endif
|
2026-02-07 17:59:40 -08:00
|
|
|
std::signal(SIGSEGV, crashHandler);
|
|
|
|
|
std::signal(SIGABRT, crashHandler);
|
|
|
|
|
std::signal(SIGFPE, crashHandler);
|
|
|
|
|
std::signal(SIGTERM, crashHandler);
|
|
|
|
|
std::signal(SIGINT, crashHandler);
|
2026-02-02 12:24:50 -08:00
|
|
|
try {
|
2026-02-22 06:32:49 -08:00
|
|
|
wowee::core::Logger::getInstance().setLogLevel(readLogLevelFromEnv());
|
2026-02-02 23:22:58 -08:00
|
|
|
LOG_INFO("=== Wowee Native Client ===");
|
2026-02-02 12:24:50 -08:00
|
|
|
LOG_INFO("Starting application...");
|
|
|
|
|
|
|
|
|
|
wowee::core::Application app;
|
|
|
|
|
|
|
|
|
|
if (!app.initialize()) {
|
|
|
|
|
LOG_FATAL("Failed to initialize application");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
app.run();
|
|
|
|
|
app.shutdown();
|
|
|
|
|
|
|
|
|
|
LOG_INFO("Application exited successfully");
|
2026-02-18 17:38:08 -08:00
|
|
|
#ifdef __linux__
|
2026-02-07 18:33:14 -08:00
|
|
|
if (g_emergencyDisplay) { XCloseDisplay(g_emergencyDisplay); g_emergencyDisplay = nullptr; }
|
2026-02-18 17:38:08 -08:00
|
|
|
#endif
|
2026-02-02 12:24:50 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
catch (const std::exception& e) {
|
2026-02-07 17:59:40 -08:00
|
|
|
releaseMouseGrab();
|
2026-02-02 12:24:50 -08:00
|
|
|
LOG_FATAL("Unhandled exception: ", e.what());
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
catch (...) {
|
2026-02-07 17:59:40 -08:00
|
|
|
releaseMouseGrab();
|
2026-02-02 12:24:50 -08:00
|
|
|
LOG_FATAL("Unknown exception occurred");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|