From 5e26c502ee23524862a75d286b9eb2a8b123c30e Mon Sep 17 00:00:00 2001 From: Laan Tungir Date: Mon, 20 Jul 2026 17:38:19 -0400 Subject: [PATCH] v0.0.54 - Update vendored nostr_core_lib to v0.6.9 (NIP-03 OpenTimestamps expansion, prefixed n_signer verbs) --- VERSION | 2 +- src/nostr_inject.c | 43 ++++++++++++++++++++ src/tab_manager.c | 97 +++++++++++++++++++++++++++++++++++++++++++++- src/version.h | 4 +- 4 files changed, 141 insertions(+), 5 deletions(-) diff --git a/VERSION b/VERSION index f2e654c..c97e08f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.0.53 +0.0.54 diff --git a/src/nostr_inject.c b/src/nostr_inject.c index 19ceab6..82a5174 100644 --- a/src/nostr_inject.c +++ b/src/nostr_inject.c @@ -128,6 +128,39 @@ static const char *NOSTR_SHIM_JS = " }\n" "})();\n"; +/* Wheel-scroll workaround for WebKitGTK. + * + * On some pages (e.g. jumble.social) WebKitGTK dispatches JS wheel events + * but does not perform the native scroll action — so the scrollbar works + * (native GDK scroll) but the mouse wheel doesn't scroll the page. This + * script installs a non-passive wheel listener on window that, when the + * page's main scroll container is the document (the common case), calls + * preventDefault() and manually scrolls by the wheel delta. It only + * intervenes when the target is the document/body/html or an element with + * no own scroll (overflow: visible), so nested scroll containers (which + * WebKitGTK handles correctly) are not broken. */ +static const char *WHEEL_SCROLL_JS = +"(function(){\n" +" 'use strict';\n" +" function isMainScrollTarget(el){\n" +" if(!el) return false;\n" +" if(el===document||el===document.documentElement||el===document.body) return true;\n" +" var cs=getComputedStyle(el);\n" +" return (cs.overflowY==='visible'||cs.overflowY==='') && el.scrollHeight<=el.clientHeight;\n" +" }\n" +" window.addEventListener('wheel',function(e){\n" +" if(e.defaultPrevented) return;\n" +" if(!isMainScrollTarget(e.target)) return;\n" +" var html=document.documentElement;\n" +" if(html.scrollHeight<=html.clientHeight) return;\n" +" e.preventDefault();\n" +" var dy=e.deltaY;\n" +" if(e.deltaMode===1) dy*=40;\n" +" else if(e.deltaMode===2) dy*=html.clientHeight;\n" +" window.scrollBy(0,dy);\n" +" },{capture:false,passive:false});\n" +"})();\n"; + void nostr_inject_setup(WebKitWebView *webview) { WebKitUserContentManager *manager = webkit_web_view_get_user_content_manager(webview); @@ -148,4 +181,14 @@ void nostr_inject_setup(WebKitWebView *webview) { /* The manager takes ownership of the script. */ webkit_user_script_unref(script); + /* Wheel-scroll workaround — see WHEEL_SCROLL_JS comment above. */ + WebKitUserScript *wheel = webkit_user_script_new( + WHEEL_SCROLL_JS, + WEBKIT_USER_CONTENT_INJECT_ALL_FRAMES, + WEBKIT_USER_SCRIPT_INJECT_AT_DOCUMENT_START, + NULL, + NULL + ); + webkit_user_content_manager_add_script(manager, wheel); + webkit_user_script_unref(wheel); } diff --git a/src/tab_manager.c b/src/tab_manager.c index 8294af3..bd2a7e7 100644 --- a/src/tab_manager.c +++ b/src/tab_manager.c @@ -176,6 +176,10 @@ static gboolean on_window_focus_in(GtkWidget *widget, gpointer user_data); static void on_aux_window_destroy(GtkWidget *widget, gpointer user_data); +static void on_notebook_switch_page(GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + gpointer user_data); /* Forward declarations for signal handlers used by tab_manager_new_window * (which is defined before these handlers in the file). */ static void on_load_changed(WebKitWebView *webview, @@ -1208,6 +1212,11 @@ static GtkWidget *tab_manager_new_window(const char *url, * stays pointing at the main window's image). */ setup_notebook_action_widgets(notebook, FALSE); + /* Grab focus on the webview when a tab is switched to (same as the + * main notebook) so wheel/scroll events work in auxiliary windows. */ + g_signal_connect(notebook, "switch-page", + G_CALLBACK(on_notebook_switch_page), NULL); + /* Build a window-level GtkPaned: left = sidebar container, right = * notebook. The sidebar is per-window (not per-tab), so it persists * across tab switches within this window. Hidden by default. */ @@ -2644,6 +2653,56 @@ static void bookmark_bar_refresh_all(void *user_data) { } } +/* Grab GTK focus on the webview when the user clicks anywhere in it. + * Also called from the notebook "switch-page" handler so the webview + * gets focus whenever its tab becomes active. + * + * Without this, the webview frequently doesn't have GTK focus (the URL + * entry grabs it on new-tab, toolbar buttons steal it, etc.), and + * WebKitGTK then drops mouse-wheel scroll events because the webview + * isn't the GTK focus widget — the scrollbar still works (native GDK + * scroll) but the wheel doesn't. This is especially visible on pages + * like Jumble that have focusable sidebar elements. */ +static void webview_grab_focus(WebKitWebView *webview) { + if (webview == NULL) return; + GtkWidget *w = GTK_WIDGET(webview); + if (!gtk_widget_has_focus(w)) { + gtk_widget_grab_focus(w); + } +} + +static gboolean on_webview_button_press(GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) { + (void)event; + (void)user_data; + if (widget != NULL && !gtk_widget_has_focus(widget)) { + gtk_widget_grab_focus(widget); + } + return FALSE; +} + +/* notebook "switch-page" handler: grab focus on the newly-selected tab's + * webview so wheel/scroll events work without the user having to click + * the page first. The page_num is the notebook page index; we map it to + * our tab array via the tab_info_t stored on the page widget. */ +static void on_notebook_switch_page(GtkNotebook *notebook, + GtkWidget *page, + guint page_num, + gpointer user_data) { + (void)notebook; + (void)page_num; + (void)user_data; + if (page == NULL) return; + /* The page widget is the tab_info_t->page GtkBox. The webview is + * packed into it as a child. Find the webview by walking children. */ + tab_info_t *tab = (tab_info_t *)g_object_get_data(G_OBJECT(page), + "tab-info"); + if (tab != NULL && tab->webview != NULL) { + webview_grab_focus(tab->webview); + } +} + static tab_info_t *tab_create(const char *url) { const browser_settings_t *s = settings_get(); @@ -2723,8 +2782,25 @@ static tab_info_t *tab_create(const char *url) { g_signal_connect(G_OBJECT(tab->webview), "key-press-event", G_CALLBACK(on_key_press), NULL); + /* Grab GTK focus on button-press so the webview receives wheel/scroll + * events. Without this, clicking a focusable element inside the page + * (e.g. a sidebar button) can leave GTK focus on a sibling widget (URL + * entry, toolbar button), and WebKitGTK then drops mouse-wheel events + * because the webview isn't the GTK focus widget — the scrollbar still + * works (it's a native GDK scroll on the widget) but the wheel doesn't. + * Grabbing focus on click fixes wheel scrolling on pages like Jumble + * that have focusable sidebar elements. We return FALSE so WebKit still + * receives the click normally. */ + g_signal_connect(G_OBJECT(tab->webview), "button-press-event", + G_CALLBACK(on_webview_button_press), NULL); + /* Build the per-tab page: toolbar on top, webview below. */ tab->page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + /* Store the tab_info_t pointer on the page widget so the notebook + * "switch-page" handler (on_notebook_switch_page) can find the webview + * to grab focus. Uses a weak ref (no destroy notify) — the tab_info_t + * is freed separately in tab_manager_close_tab. */ + g_object_set_data(G_OBJECT(tab->page), "tab-info", tab); GtkWidget *toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4); gtk_widget_set_margin_top(toolbar, 4); @@ -2888,8 +2964,21 @@ static tab_info_t *tab_create(const char *url) { g_signal_connect(tab->webview, "create", G_CALLBACK(on_create_webview), tab); - /* Load the URL. */ - webkit_web_view_load_uri(tab->webview, default_url); + /* Load the URL. + * + * IMPORTANT: When this webview is being created in response to the + * "create" signal (target="_blank" / window.open()), g_target_related_view + * is set. In that case WebKit already has a pending NavigationAction with + * WindowFeatures that it will apply to the returned webview itself. If we + * call webkit_web_view_load_uri() here first, our load races with WebKit's + * own navigation setup and the std::optional never gets + * engaged — leading to the assertion crash: + * _M_get() const: Assertion 'this->_M_is_engaged()' failed. + * So we skip the explicit load and let WebKit drive the navigation. The + * tab's URL bar / title were already initialized from default_url above. */ + if (g_target_related_view == NULL) { + webkit_web_view_load_uri(tab->webview, default_url); + } g_free(default_url); return tab; @@ -3347,6 +3436,10 @@ void tab_manager_init(GtkContainer *parent, * keep targeting the auxiliary window's tab. */ g_signal_connect(window, "focus-in-event", G_CALLBACK(on_window_focus_in), g_notebook); + /* Grab focus on the webview when a tab is switched to, so wheel/scroll + * events work without the user having to click the page first. */ + g_signal_connect(g_notebook, "switch-page", + G_CALLBACK(on_notebook_switch_page), NULL); g_active_window = window; g_active_notebook = g_notebook; g_active_ws = &g_main_window; diff --git a/src/version.h b/src/version.h index f175337..176f1dc 100644 --- a/src/version.h +++ b/src/version.h @@ -11,9 +11,9 @@ #ifndef SOVEREIGN_BROWSER_VERSION_H #define SOVEREIGN_BROWSER_VERSION_H -#define SB_VERSION "v0.0.53" +#define SB_VERSION "v0.0.54" #define SB_VERSION_MAJOR 0 #define SB_VERSION_MINOR 0 -#define SB_VERSION_PATCH 53 +#define SB_VERSION_PATCH 54 #endif /* SOVEREIGN_BROWSER_VERSION_H */