detached 81a156d

refactor(browser): defer content blocking initialization to main loop

Move setupContentBlocking from goroutine sleep pattern to explicit main loop
execution via RunOnMainThread to ensure GTK is fully ready before loading
content filters.
commit
81a156ddaaa440fb981439cdb058b3379060bc8a
author
bnema · · 2025-12-06 20:52 UTC
parent
3ba3877
signature
unsigned
2 files · +12 -9
M internal/app/browser/browser.go +8 -9
@@ -281,15 +281,6 @@ func (app *BrowserApp) Run() {
281281 // Register custom scheme resolver for "dumb://" URIs (will be applied after WebView creation)
282282 webkit.RegisterURIScheme("dumb", app.schemeHandler.Handle)
283283
284- // DEFERRED: Initialize content blocking AFTER window shows to speed up boot
285- // Content filters load from cache quickly (~50ms) and apply to new navigations
286- go func() {
287- time.Sleep(100 * time.Millisecond) // Let window render first
288- if err := app.setupContentBlocking(); err != nil {
289- logging.Warn(fmt.Sprintf("Warning: failed to setup content blocking: %v", err))
290- }
291- }()
292-
293284 // Create and setup WebView (this also creates TabManager which creates more WebViews)
294285 if err := app.createWebView(); err != nil {
295286 logging.Warn(fmt.Sprintf("Warning: failed to create WebView: %v", err))
@@ -428,6 +419,14 @@ func (app *BrowserApp) setupSignalHandling() {
428419 // runMainLoop starts the appropriate main loop based on WebKit availability
429420 func (app *BrowserApp) runMainLoop() {
430421 if webkit.IsNativeAvailable() {
422+ // Schedule content blocking initialization to run on the first main loop iteration
423+ // This ensures GTK is fully ready before we start loading filters
424+ webkit.RunOnMainThread(func() {
425+ if err := app.setupContentBlocking(); err != nil {
426+ logging.Warn(fmt.Sprintf("Warning: failed to setup content blocking: %v", err))
427+ }
428+ })
429+
431430 logging.Info(fmt.Sprintf("Entering GTK main loop…"))
432431 webkit.RunMainLoop()
433432 logging.Info(fmt.Sprintf("GTK main loop exited"))
@@ -281,15 +281,6 @@ func (app *BrowserApp) Run() {
281 // Register custom scheme resolver for "dumb://" URIs (will be applied after WebView creation)281 // Register custom scheme resolver for "dumb://" URIs (will be applied after WebView creation)
282 webkit.RegisterURIScheme("dumb", app.schemeHandler.Handle)282 webkit.RegisterURIScheme("dumb", app.schemeHandler.Handle)
283 283
284- // DEFERRED: Initialize content blocking AFTER window shows to speed up boot
285- // Content filters load from cache quickly (~50ms) and apply to new navigations
286- go func() {
287- time.Sleep(100 * time.Millisecond) // Let window render first
288- if err := app.setupContentBlocking(); err != nil {
289- logging.Warn(fmt.Sprintf("Warning: failed to setup content blocking: %v", err))
290- }
291- }()
292-
293 // Create and setup WebView (this also creates TabManager which creates more WebViews)284 // Create and setup WebView (this also creates TabManager which creates more WebViews)
294 if err := app.createWebView(); err != nil {285 if err := app.createWebView(); err != nil {
295 logging.Warn(fmt.Sprintf("Warning: failed to create WebView: %v", err))286 logging.Warn(fmt.Sprintf("Warning: failed to create WebView: %v", err))
@@ -428,6 +419,14 @@ func (app *BrowserApp) setupSignalHandling() {
428 // runMainLoop starts the appropriate main loop based on WebKit availability419 // runMainLoop starts the appropriate main loop based on WebKit availability
429 func (app *BrowserApp) runMainLoop() {420 func (app *BrowserApp) runMainLoop() {
430 if webkit.IsNativeAvailable() {421 if webkit.IsNativeAvailable() {
422+ // Schedule content blocking initialization to run on the first main loop iteration
423+ // This ensures GTK is fully ready before we start loading filters
424+ webkit.RunOnMainThread(func() {
425+ if err := app.setupContentBlocking(); err != nil {
426+ logging.Warn(fmt.Sprintf("Warning: failed to setup content blocking: %v", err))
427+ }
428+ })
429+
431 logging.Info(fmt.Sprintf("Entering GTK main loop…"))430 logging.Info(fmt.Sprintf("Entering GTK main loop…"))
432 webkit.RunMainLoop()431 webkit.RunMainLoop()
433 logging.Info(fmt.Sprintf("GTK main loop exited"))432 logging.Info(fmt.Sprintf("GTK main loop exited"))
M internal/app/browser/workspace_pane_ops.go +4 -0
@@ -971,6 +971,10 @@ func (wm *WorkspaceManager) cleanupPane(node *paneNode, generation uint) {
971971
972972 if node.pane != nil {
973973 pane := node.pane
974+ // Unregister from filtering BEFORE cleanup to prevent stale pointer callbacks
975+ if pane.webView != nil {
976+ wm.app.UnregisterWebViewFromFiltering(pane.webView)
977+ }
974978 pane.Cleanup()
975979 pane.CleanupFromWorkspace(wm)
976980 if pane.webView != nil {
@@ -971,6 +971,10 @@ func (wm *WorkspaceManager) cleanupPane(node *paneNode, generation uint) {
971 971
972 if node.pane != nil {972 if node.pane != nil {
973 pane := node.pane973 pane := node.pane
974+ // Unregister from filtering BEFORE cleanup to prevent stale pointer callbacks
975+ if pane.webView != nil {
976+ wm.app.UnregisterWebViewFromFiltering(pane.webView)
977+ }
974 pane.Cleanup()978 pane.Cleanup()
975 pane.CleanupFromWorkspace(wm)979 pane.CleanupFromWorkspace(wm)
976 if pane.webView != nil {980 if pane.webView != nil {

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 9

Tags 42

↑↓ moveenter openesc close