web: Move over to contrib.glfw3

This commit is contained in:
WerWolv
2026-02-12 21:57:20 +01:00
parent 800a24b42e
commit 060f0e6e56
10 changed files with 77 additions and 145 deletions

View File

@@ -38,7 +38,8 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../lib/external/libromfs ${CMAKE
add_dependencies(imhex_all main)
if (EMSCRIPTEN)
target_link_options(main PRIVATE -sUSE_GLFW=3 -sUSE_PTHREADS=1 -sALLOW_MEMORY_GROWTH=1 -Wno-pthreads-mem-growth)
target_compile_options(main PRIVATE --use-port=contrib.glfw3)
target_link_options(main PRIVATE --use-port=contrib.glfw3 -sUSE_PTHREADS=1 -sALLOW_MEMORY_GROWTH=1 -Wno-pthreads-mem-growth)
target_link_options(main PRIVATE -sTOTAL_MEMORY=134217728)
target_link_options(main PRIVATE -sMAX_WEBGL_VERSION=2)
target_link_options(main PRIVATE -sGL_UNSAFE_OPTS=0)

View File

@@ -67,6 +67,17 @@ namespace hex::init {
log::debug("OpenGL Renderer: '{}'", glRendererString);
log::debug("OpenGL Version String: '{}'", glVersionString);
log::debug("OpenGL Shading Language Version: '{}'", glShadingLanguageVersion);
log::debug("GLFW Backend: '{}'", [] {
switch (glfwGetPlatform()) {
case GLFW_PLATFORM_WIN32: return "Win32";
case GLFW_PLATFORM_COCOA: return "Cocoa";
case GLFW_PLATFORM_X11: return "X11";
case GLFW_PLATFORM_WAYLAND: return "Wayland";
case GLFW_PLATFORM_NULL: return "null";
case GLFW_PLATFORM_UNAVAILABLE: return "Unavailable";
default: return "Unknown";
}
}());
ImHexApi::System::impl::setGPUVendor(glVendorString);
ImHexApi::System::impl::setGLRenderer(glRendererString);
@@ -462,6 +473,8 @@ namespace hex::init {
log::error("GLFW Error [{:05X}] : {}", errorCode, desc);
});
glfwDefaultWindowHints();
#if defined(OS_LINUX)
#if defined(GLFW_WAYLAND_APP_ID)
glfwWindowHintString(GLFW_WAYLAND_APP_ID, "imhex");

View File

@@ -112,7 +112,7 @@ namespace hex {
glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_TRUE);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_DECORATED, ImHexApi::System::isBorderlessWindowModeEnabled() ? GL_FALSE : GL_TRUE);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_TRUE);

View File

@@ -1,9 +1,13 @@
#include <GLFW/glfw3.h>
#include "window.hpp"
#include "hex/api/imhex_api/system.hpp"
#if defined(OS_WEB)
#include <emscripten.h>
#include <emscripten/html5.h>
#include <GLFW/emscripten_glfw3.h>
#include <hex/api/imhex_api/system.hpp>
#include <hex/api/events/events_gui.hpp>
@@ -16,20 +20,6 @@
#include <imgui.h>
#include <imgui_internal.h>
// Function used by c++ to get the size of the html canvas
EM_JS(int, canvas_get_width, (), {
return Module.canvas.width;
});
// Function used by c++ to get the size of the html canvas
EM_JS(int, canvas_get_height, (), {
return Module.canvas.height;
});
// Function called by javascript
EM_JS(void, resizeCanvas, (), {
js_resizeCanvas();
});
EM_JS(bool, isMacOS, (), {
return navigator.userAgent.indexOf('Mac OS X') != -1
@@ -54,6 +44,11 @@ extern "C" void handleThemeChange() {
hex::EventOSThemeChanged::post();
}
EMSCRIPTEN_KEEPALIVE
extern "C" void updateFramebufferSize(int width, int height) {
glfwSetWindowSize(hex::ImHexApi::System::getMainWindowHandle(), width, height);
}
EM_JS(void, setupInputModeListener, (), {
Module.canvas.addEventListener('mousedown', function() {
@@ -79,9 +74,12 @@ namespace hex {
void Window::configureGLFW() {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
glfwWindowHint(GLFW_DECORATED, GL_FALSE);
glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GLFW_FALSE);
glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
emscripten::glfw3::SetNextWindowCanvasSelector("#canvas");
}
void Window::initNative() {
@@ -101,8 +99,23 @@ namespace hex {
});
}
static float calculateNativeScale(GLFWwindow *window) {
int windowW, windowH;
int displayW, displayH;
glfwGetWindowSize(window, &windowW, &windowH);
glfwGetFramebufferSize(window, &displayW, &displayH);
const auto xScale = (windowW > 0) ? float(displayW) / windowW : 1.0f;
const auto yScale = (windowH > 0) ? float(displayH) / windowH : 1.0f;
auto scaleFactor = std::midpoint(xScale, yScale);
if (scaleFactor <= 0.0F)
scaleFactor = 1.0F;
return scaleFactor;
}
void Window::setupNativeWindow() {
resizeCanvas();
setupThemeListener();
setupInputModeListener();
fixCanvasInPlace();
@@ -123,15 +136,20 @@ namespace hex {
glfwSetWindowRefreshCallback(m_window, [](GLFWwindow *window) {
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
resizeCanvas();
win->fullFrame();
});
if (themeFollowSystem)
EventOSThemeChanged::post();
if (isMacOS())
if (emscripten::glfw3::IsRuntimePlatformApple())
ShortcutManager::enableMacOSMode();
glfwSetWindowAttrib(m_window, GLFW_SCALE_FRAMEBUFFER, GLFW_TRUE);
glfwShowWindow(m_window);
emscripten::glfw3::MakeCanvasResizable(m_window, "#canvas-wrapper");
ImHexApi::System::impl::setNativeScale(calculateNativeScale(m_window));
EventDPIChanged::post(1.0, ImHexApi::System::getBackingScaleFactor());
}
void Window::beginNativeWindowFrame() {
@@ -140,40 +158,18 @@ namespace hex {
void Window::endNativeWindowFrame() {
static float prevScaleFactor = 0;
const float currScaleFactor = MAIN_THREAD_EM_ASM_DOUBLE({
try {
return window.devicePixelRatio;
} catch (e) {
return 1.0;
}
});
const float currScaleFactor = ImHexApi::System::getBackingScaleFactor();
if (prevScaleFactor != 0 && prevScaleFactor != currScaleFactor) {
EventDPIChanged::post(prevScaleFactor, currScaleFactor);
resizeCanvas();
ImHexApi::System::impl::setNativeScale(currScaleFactor);
ImHexApi::System::impl::setNativeScale(calculateNativeScale(m_window));
ThemeManager::reapplyCurrentTheme();
}
static i32 prevWidth = 0;
static i32 prevHeight = 0;
auto width = canvas_get_width();
auto height = canvas_get_height();
if (prevWidth != width || prevHeight != height) {
// Size has changed
prevWidth = width;
prevHeight = height;
this->resize(width, height);
resizeCanvas();
}
prevScaleFactor = currScaleFactor;
glfwSetWindowSize(m_window, EM_ASM_INT({ return document.getElementById("canvas-wrapper").clientWidth; }), EM_ASM_INT({ return document.getElementById("canvas-wrapper").clientHeight; }));
}
}

View File

@@ -401,7 +401,7 @@ namespace hex {
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
} else {
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1);
}
glfwWindowHint(GLFW_DECORATED, ImHexApi::System::isBorderlessWindowModeEnabled() ? GL_FALSE : GL_TRUE);

View File

@@ -1019,8 +1019,14 @@ namespace hex {
glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
glfwWindowHint(GLFW_FLOATING, GLFW_FALSE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE);
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API);
// Don't hide the window on the web build, otherwise the mouse cursor offset will not
// be calculated correctly if the canvas is not filling the entire screen
#if !defined(OS_WEB)
glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
#endif
configureGLFW();
if (initialWindowProperties.has_value()) {