diff options
| -rw-r--r-- | include/saffronwebkit.h | 1 | ||||
| -rw-r--r-- | meson.build | 3 | ||||
| -rw-r--r-- | src/sfwk-wpe.c | 135 | ||||
| -rw-r--r-- | tests/sfwk-minimal.c | 18 |
4 files changed, 127 insertions, 30 deletions
diff --git a/include/saffronwebkit.h b/include/saffronwebkit.h index 1cb75f3..d15ace5 100644 --- a/include/saffronwebkit.h +++ b/include/saffronwebkit.h @@ -48,6 +48,7 @@ typedef struct { typedef struct { SaffronWidget base; SFWKContext* context; + SaffronWindow* window; // just for the GL context char* url; int w, h; diff --git a/meson.build b/meson.build index 8c197d6..ea20db0 100644 --- a/meson.build +++ b/meson.build @@ -5,8 +5,10 @@ wpe_dep = dependency('wpe-webkit-2.0') wpe_platform_dep = dependency('wpe-platform-2.0') gles2_dep = dependency('glesv2') +egl_dep = dependency('egl') deps = [ + egl_dep, gles2_dep, wpe_dep, wpe_platform_dep, @@ -24,6 +26,7 @@ sfwk_lib = static_library('saffronwebkit', sources, include_directories: inc, de sfwk_dep = declare_dependency(link_with: sfwk_lib, include_directories: inc, dependencies: deps) test_deps = [ + egl_dep, gles2_dep, wpe_dep, wpe_platform_dep, diff --git a/src/sfwk-wpe.c b/src/sfwk-wpe.c index d7cd128..e69d558 100644 --- a/src/sfwk-wpe.c +++ b/src/sfwk-wpe.c @@ -16,7 +16,11 @@ #include <SDL3/SDL_egl.h> #include <SDL3/SDL_opengles2.h> #include <saffronwebkit.h> +#include <sys/types.h> +#include <unistd.h> +static EGLContext saved_egl_context = EGL_NO_CONTEXT; +static EGLDisplay saved_egl_display = EGL_NO_DISPLAY; G_DECLARE_FINAL_TYPE(WPEViewSDL3, wpe_view_sdl3, WPE, VIEW_SDL3, WPEView) G_DECLARE_FINAL_TYPE(WPEToplevelSDL3, wpe_toplevel_sdl3, WPE, TOPLEVEL_SDL3, WPEToplevel) @@ -26,6 +30,21 @@ G_DEFINE_FINAL_TYPE(WPEViewSDL3, wpe_view_sdl3, WPE_TYPE_VIEW) G_DEFINE_FINAL_TYPE(WPEToplevelSDL3, wpe_toplevel_sdl3, WPE_TYPE_TOPLEVEL) G_DEFINE_FINAL_TYPE(WPEDisplaySDL3, wpe_display_sdl3, WPE_TYPE_DISPLAY) +static void on_load_changed(WebKitWebView *web_view, WebKitLoadEvent load_event, gpointer userdata) { + const char* event_str = "UNKNOWN"; + switch(load_event) { + case WEBKIT_LOAD_STARTED: event_str = "STARTED"; break; + case WEBKIT_LOAD_REDIRECTED: event_str = "REDIRECTED"; break; + case WEBKIT_LOAD_COMMITTED: event_str = "COMMITTED"; break; + case WEBKIT_LOAD_FINISHED: event_str = "FINISHED"; break; + } + g_debug("=== WEBKIT LOAD EVENT: %s ===", event_str); +} + +static void on_load_failed(WebKitWebView *web_view, WebKitLoadEvent load_event, const char *failing_uri, GError *error, gpointer userdata) { + g_warning("=== WEBKIT LOAD FAILED === URI: %s, Error: %s", failing_uri, error->message); +} + static void wpe_toplevel_sdl3_ensure_texture(WPEToplevelSDL3 *self, SDL_Renderer* renderer, SDL_PixelFormat format, int width, int height) { @@ -43,10 +62,12 @@ wpe_toplevel_sdl3_ensure_texture(WPEToplevelSDL3 *self, SDL_Renderer* renderer, static gboolean wpe_toplevel_sdl3_render(WPEToplevelSDL3 *self, SDL_Renderer* renderer, WPEView *view [[maybe_unused]], WPEBuffer *buffer, GError **error) { - // g_debug("%s: toplevel=%p, view=%p, buffer=%p is a %s", G_STRFUNC, self, view, buffer, G_OBJECT_TYPE_NAME(buffer)); + g_debug("SFWK: wpe_toplevel_sdl3_render running"); + g_debug("%s: toplevel=%p, view=%p, buffer=%p is a %s", G_STRFUNC, self, view, buffer, G_OBJECT_TYPE_NAME(buffer)); int buffer_width = wpe_buffer_get_width(buffer); int buffer_height = wpe_buffer_get_height(buffer); + g_debug("Buffer size: %dx%d", buffer_width, buffer_height); if (buffer) { WPEDisplaySDL3 *display = (WPEDisplaySDL3*) wpe_toplevel_get_display((WPEToplevel*) self); @@ -103,11 +124,11 @@ wpe_toplevel_sdl3_render(WPEToplevelSDL3 *self, SDL_Renderer* renderer, WPEView return FALSE; } } else { + g_debug("SFWK: No buffer found, clearing to white"); SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); SDL_RenderClear(renderer); } - SDL_RenderPresent(renderer); return TRUE; } @@ -307,9 +328,6 @@ wpe_display_sdl3_finalize(GObject *object) self->destroyImage = NULL; self->imageTargetTexture2DOES = NULL; - g_clear_pointer(&self->gl_context, SDL_GL_DestroyContext); - g_clear_pointer(&self->hidden_window, SDL_DestroyWindow); - if (self->init_flags) { SDL_QuitSubSystem(self->init_flags); self->init_flags = 0; @@ -322,28 +340,21 @@ static gboolean wpe_display_sdl3_connect(WPEDisplay *display, GError **error) { WPEDisplaySDL3 *self = WPE_DISPLAY_SDL3(display); - + self->egl_display = SDL_EGL_GetCurrentDisplay(); - + if (self->egl_display == EGL_NO_DISPLAY) { g_set_error(error, WPE_DISPLAY_ERROR, WPE_DISPLAY_ERROR_CONNECTION_FAILED, - "Could not get SDL-managed EGL display: %s", SDL_GetError()); + "No active EGL display. Saffron must initialize OpenGL first."); return FALSE; } - + self->destroyImage = (PFNEGLDESTROYIMAGEKHRPROC) SDL_EGL_GetProcAddress("eglDestroyImageKHR"); self->imageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) SDL_EGL_GetProcAddress("glEGLImageTargetTexture2DOES"); - g_debug("%s: done, eglDestroyImageKHR=%p, glEGLImageTargetTexture2DOES=%p", G_STRFUNC, - self->destroyImage, self->imageTargetTexture2DOES); - - if (!self->destroyImage) { - g_set_error_literal(error, WPE_DISPLAY_ERROR, WPE_DISPLAY_ERROR_CONNECTION_FAILED, - "EGL does not support eglDestroyImageKHR"); - return FALSE; - } - + + g_debug("%s: Using existing EGL display %p", G_STRFUNC, self->egl_display); return TRUE; } @@ -479,38 +490,86 @@ SFWKContext* sfwk_init() { SFWKContext* context = g_new0(SFWKContext, 1); context->main_context = g_main_context_new_with_flags(G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING); + g_main_context_push_thread_default(context->main_context); context->display = g_object_new(wpe_display_sdl3_get_type(), NULL); // ensure_initialized will do the GL context later, hopefully - + return context; } static bool sfwk_webview_ensure_initialized(SFWKWebView* webview) { + g_debug("SFWK: ensure initialized called"); if (webview->wpe.initialized) return true; - EGLDisplay display = SDL_EGL_GetCurrentDisplay(); - if (display == EGL_NO_DISPLAY) { + g_debug("SFWK: checking for window reference"); + if (!webview->window) { + g_debug("sfwk: no window reference, cannot get GL context"); + return false; + } + + g_debug("SFWK: checking for GL context in window"); + SDL_GLContext ctx = webview->window->gl_context; + if (!ctx) { + g_debug("sfwk: no gl context in window?? good luck"); + return false; + } + + g_debug("SFWK: making GL context current..."); + if (!SDL_GL_MakeCurrent(webview->window->sdl_window, ctx)) { + g_debug("SFWK: SDL_GL_MakeCurrent failed: %s", SDL_GetError()); return false; } + saved_egl_context = eglGetCurrentContext(); + saved_egl_display = eglGetCurrentDisplay(); + + if (saved_egl_context == EGL_NO_CONTEXT) { + g_debug("sfwk: No current EGL context, waiting..."); + return false; + } + + g_debug("sfwk: Found current EGL context %p on display %p", saved_egl_context, saved_egl_display); + g_autoptr(GError) error = NULL; if (!wpe_display_connect(webview->context->display, &error)) { + g_warning("sfwk: Failed to connect display: %s", error->message); return false; } + + WPEDisplaySDL3 *display_impl = WPE_DISPLAY_SDL3(webview->context->display); + display_impl->egl_display = saved_egl_display; + + // webview->wpe.toplevel = wpe_toplevel_sdl3_new(webview->context->display); + // webview->wpe.wpeview = wpe_view_sdl3_new(webview->context->display); + // ((WPEViewSDL3*)webview->wpe.wpeview)->userdata = webview; + // wpe_view_set_toplevel(webview->wpe.wpeview, webview->wpe.toplevel); + // + // g_debug("Setting toplevel size to %dx%d", webview->w, webview->h); + // wpe_toplevel_resize(webview->wpe.toplevel, webview->w, webview->h); + // + // webview->wpe.wkwebview = g_object_new(WEBKIT_TYPE_WEB_VIEW, "display", webview->context->display, NULL); + // g_debug("sfwk: WebKitWebView created: %p", webview->wpe.wkwebview); - webview->wpe.toplevel = wpe_toplevel_sdl3_new(webview->context->display); - webview->wpe.wpeview = wpe_view_sdl3_new(webview->context->display); + webview->wpe.wkwebview = g_object_new(WEBKIT_TYPE_WEB_VIEW, "display", webview->context->display, NULL); + webview->wpe.wpeview = webkit_web_view_get_wpe_view(webview->wpe.wkwebview); ((WPEViewSDL3*)webview->wpe.wpeview)->userdata = webview; - wpe_view_set_toplevel(webview->wpe.wpeview, webview->wpe.toplevel); - webview->wpe.wkwebview = g_object_new(WEBKIT_TYPE_WEB_VIEW, "display", webview->context->display, NULL); + webview->wpe.toplevel = wpe_view_get_toplevel(webview->wpe.wpeview); + + g_debug("Setting toplevel size to %dx%d", webview->w, webview->h); + wpe_toplevel_resize(webview->wpe.toplevel, webview->w, webview->h); + + g_signal_connect(webview->wpe.wkwebview, "load-changed", G_CALLBACK(on_load_changed), webview); + g_signal_connect(webview->wpe.wkwebview, "load-failed", G_CALLBACK(on_load_failed), webview); if (webview->url) { webkit_web_view_load_uri(webview->wpe.wkwebview, webview->url); + g_debug("sfwk: Loading URL: %s", webview->url); } - + webview->wpe.initialized = TRUE; + g_debug("sfwk: WPE initialized successfully"); return true; } @@ -519,14 +578,31 @@ static void sfwk_webview_draw(SaffronWidget* widget, SDL_Renderer* renderer) { webview->renderer = renderer; if (sfwk_webview_ensure_initialized(webview)) { + g_debug("SFWK WebView draw: iterating context"); + g_main_context_iteration(webview->context->main_context, FALSE); + static gboolean first_frame = TRUE; + if (first_frame) { + wpe_toplevel_resize(webview->wpe.toplevel, widget->w, widget->h); + wpe_view_resized(webview->wpe.wpeview, widget->w, widget->h); + first_frame = FALSE; + } + WPEToplevelSDL3* toplevel = (WPEToplevelSDL3*)webview->wpe.toplevel; if (toplevel && toplevel->texture) { - SDL_RenderTexture(renderer, toplevel->texture, NULL, NULL); + SDL_FRect dst = { widget->x, widget->y, widget->w, widget->h }; + SDL_RenderTexture(renderer, toplevel->texture, NULL, &dst); + + GLenum err = glGetError(); + if (err != GL_NO_ERROR) { + g_warning("OpenGL error: 0x%x", err); + } return; } } - - // if its not init just be blank, too bad so sad, notmyfault + + // Draw a loading indicator + SDL_SetRenderDrawColor(renderer, 240, 240, 240, 255); + SDL_RenderFillRect(renderer, &(SDL_FRect){0, 0, widget->w, widget->h}); } void sfwk_process_event(SFWKContext *context, SFWKWebView* webview, SDL_Event *event) { @@ -547,6 +623,7 @@ SFWKWebView* sfwk_webview_new(SFWKContext* context, const char* url, int w, int webview->context = context; webview->url = strdup(url); webview->wpe.initialized = FALSE; + webview->window = NULL; // ensure initialized will init this later diff --git a/tests/sfwk-minimal.c b/tests/sfwk-minimal.c index 192dbe6..68dcd3c 100644 --- a/tests/sfwk-minimal.c +++ b/tests/sfwk-minimal.c @@ -1,3 +1,4 @@ +#include "glib.h" #include <saffron.h> #include <saffronwebkit.h> @@ -10,9 +11,21 @@ bool hook_callback(SDL_Event* event) { return true; } +void btn_callback(SaffronButton* btn) { + // do nothing +} + int main() { + // if (!SDL_SetHint(SDL_HINT_VIDEO_DRIVER, "x11")) { + // printf("Warning: Could not set SDL_HINT_VIDEO_DRIVER\n"); + // } saffron_init(); + const char* driver = SDL_GetCurrentVideoDriver(); + printf("SDL is using driver: %s\n", driver); // please say x11 + + // make a button to prove the layout engine can move the webview around + SaffronButton* button = saffron_button_new(true, btn_callback, 200, 150); SaffronWindow* window = saffron_window_new("SaffronWebKit (SFWK) Test", 1024, 768); window->root->theme = SF_MACRO_DEFAULT_THEME; @@ -20,8 +33,11 @@ int main() { ctx = sfwk_init(); if (!ctx) return 1; - SFWKWebView* webview = sfwk_webview_new(ctx, "https://arslaancodes.com", 900, 600); + SFWKWebView* webview = sfwk_webview_new(ctx, "https://brickmii.xyz", 900, 600); + + saffron_widget_add_child(window->root, (SaffronWidget*)button); saffron_widget_add_child(window->root, (SaffronWidget*)webview); + webview->window = window; // so the webview can access the GL context saffron_hook_sdl_all_events(window, hook_callback, 999); |
