detached 30637f8

feat(workspace): implement popup tracking and universal window.close() handling

commit
30637f80b6ce9a7fc0e43d5c952a0c7b8f66a3e6
author
bamen · · 2025-09-20 06:03 UTC
parent
d542439
signature
unsigned
1 file · +33 -0
M internal/app/browser/workspace_manager.go +33 -0
@@ -22,6 +22,7 @@ type paneNode struct {
2222 container uintptr // GtkPaned for branch nodes, stable WebView container for leaves
2323 orientation webkit.Orientation
2424 isLeaf bool
25+ isPopup bool // Track if this is a popup pane for OAuth auto-close
2526 hoverToken uintptr
2627 }
2728
@@ -1321,6 +1322,38 @@ func (wm *WorkspaceManager) HandlePopup(source *webkit.WebView, url string) *web
13211322 return nil
13221323 }
13231324
1325+ // Mark the new pane as a popup for auto-close handling
1326+ // The viewToNode mapping is created inside insertPopupPane, so look it up now
1327+ newNode := wm.viewToNode[newView]
1328+ if newNode != nil {
1329+ newNode.isPopup = true
1330+ log.Printf("[workspace] Marked pane as popup for auto-close handling")
1331+ } else {
1332+ log.Printf("[workspace] Warning: could not find node for popup WebView in viewToNode map")
1333+ }
1334+
1335+ // Register close handler for popup auto-close on window.close()
1336+ // Always register this for popups, regardless of node lookup
1337+ newView.RegisterCloseHandler(func() {
1338+ log.Printf("[workspace] Popup requesting close via window.close()")
1339+
1340+ // Look up the node at close time
1341+ if node := wm.viewToNode[newView]; node != nil && node.isPopup {
1342+ log.Printf("[workspace] Closing popup pane")
1343+ // Brief delay to allow any final redirects to complete
1344+ time.AfterFunc(200*time.Millisecond, func() {
1345+ webkit.IdleAdd(func() bool {
1346+ if err := wm.closePane(node); err != nil {
1347+ log.Printf("[workspace] Failed to close popup pane: %v", err)
1348+ }
1349+ return false
1350+ })
1351+ })
1352+ } else {
1353+ log.Printf("[workspace] Could not find popup node for close handler")
1354+ }
1355+ })
1356+
13241357 // Load the URL if provided
13251358 if url != "" {
13261359 if err := newView.LoadURL(url); err != nil {
@@ -22,6 +22,7 @@ type paneNode struct {
22 container uintptr // GtkPaned for branch nodes, stable WebView container for leaves22 container uintptr // GtkPaned for branch nodes, stable WebView container for leaves
23 orientation webkit.Orientation23 orientation webkit.Orientation
24 isLeaf bool24 isLeaf bool
25+ isPopup bool // Track if this is a popup pane for OAuth auto-close
25 hoverToken uintptr26 hoverToken uintptr
26 }27 }
27 28
@@ -1321,6 +1322,38 @@ func (wm *WorkspaceManager) HandlePopup(source *webkit.WebView, url string) *web
1321 return nil1322 return nil
1322 }1323 }
1323 1324
1325+ // Mark the new pane as a popup for auto-close handling
1326+ // The viewToNode mapping is created inside insertPopupPane, so look it up now
1327+ newNode := wm.viewToNode[newView]
1328+ if newNode != nil {
1329+ newNode.isPopup = true
1330+ log.Printf("[workspace] Marked pane as popup for auto-close handling")
1331+ } else {
1332+ log.Printf("[workspace] Warning: could not find node for popup WebView in viewToNode map")
1333+ }
1334+
1335+ // Register close handler for popup auto-close on window.close()
1336+ // Always register this for popups, regardless of node lookup
1337+ newView.RegisterCloseHandler(func() {
1338+ log.Printf("[workspace] Popup requesting close via window.close()")
1339+
1340+ // Look up the node at close time
1341+ if node := wm.viewToNode[newView]; node != nil && node.isPopup {
1342+ log.Printf("[workspace] Closing popup pane")
1343+ // Brief delay to allow any final redirects to complete
1344+ time.AfterFunc(200*time.Millisecond, func() {
1345+ webkit.IdleAdd(func() bool {
1346+ if err := wm.closePane(node); err != nil {
1347+ log.Printf("[workspace] Failed to close popup pane: %v", err)
1348+ }
1349+ return false
1350+ })
1351+ })
1352+ } else {
1353+ log.Printf("[workspace] Could not find popup node for close handler")
1354+ }
1355+ })
1356+
1324 // Load the URL if provided1357 // Load the URL if provided
1325 if url != "" {1358 if url != "" {
1326 if err := newView.LoadURL(url); err != nil {1359 if err := newView.LoadURL(url); err != 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 8

Tags 42

↑↓ moveenter openesc close