Rules-based browser launcher for TUI + GNOME. switchyard.aly.codes
tui gnome bowser go
0

Configure Feed

Select the types of activity you want to include in your feed.

browser: properly activate launched browsers (fixes #17)

Aly Raffauf (Jan 16, 2026, 1:24 AM EST) 7e9e8928 92c9a2b5

+3 -67
+3 -67
src/browser.go
··· 5 5 import ( 6 6 "fmt" 7 7 "os" 8 - "os/exec" 9 8 "sort" 10 - "strings" 11 9 12 10 "github.com/diamondburned/gotk4/pkg/gio/v2" 13 11 ) ··· 65 63 } 66 64 67 65 func launchBrowser(b *Browser, url string) { 68 - // Get the command line from the AppInfo 69 66 cmdline := b.AppInfo.Commandline() 70 67 if cmdline == "" { 71 68 fmt.Fprintf(os.Stderr, "Error: No command line for browser %s\n", b.Name) 72 69 return 73 70 } 74 - 75 - // Replace %u, %U, %f, %F with URL 76 - cmdline = strings.ReplaceAll(cmdline, "%u", url) 77 - cmdline = strings.ReplaceAll(cmdline, "%U", url) 78 - cmdline = strings.ReplaceAll(cmdline, "%f", url) 79 - cmdline = strings.ReplaceAll(cmdline, "%F", url) 80 - 81 - // Remove other field codes 82 - for _, code := range []string{"%i", "%c", "%k"} { 83 - cmdline = strings.ReplaceAll(cmdline, code, "") 84 - } 85 - 86 - // Parse the command line 87 - parts := strings.Fields(cmdline) 88 - if len(parts) == 0 { 89 - fmt.Fprintf(os.Stderr, "Error: Empty command line for browser %s\n", b.Name) 90 - return 91 - } 92 - 93 - // When running in Flatpak, wrap with flatpak-spawn --host 94 - if os.Getenv("FLATPAK_ID") != "" && !strings.HasPrefix(parts[0], "flatpak-spawn") { 95 - parts = append([]string{"flatpak-spawn", "--host"}, parts...) 96 - } 97 - 98 - // Execute the command 99 - cmd := exec.Command(parts[0], parts[1:]...) 100 - if err := cmd.Start(); err != nil { 71 + if err := launchCommand(cmdline, url, b.AppInfo); err != nil { 101 72 fmt.Fprintf(os.Stderr, "Error launching browser: %v\n", err) 102 - return 103 73 } 104 - 105 - // Clean up asynchronously 106 - go cmd.Wait() 107 74 } 108 75 109 76 // launchBrowserAction launches a browser with a specific desktop file action (e.g., "new-private-window") 110 77 func launchBrowserAction(b *Browser, action DesktopAction, url string) { 111 - cmdline := action.Exec 112 - if cmdline == "" { 78 + if action.Exec == "" { 113 79 fmt.Fprintf(os.Stderr, "Error: No exec line for action %s\n", action.ID) 114 80 return 115 81 } 116 - 117 - // Replace %u, %U, %f, %F with URL 118 - cmdline = strings.ReplaceAll(cmdline, "%u", url) 119 - cmdline = strings.ReplaceAll(cmdline, "%U", url) 120 - cmdline = strings.ReplaceAll(cmdline, "%f", url) 121 - cmdline = strings.ReplaceAll(cmdline, "%F", url) 122 - 123 - // Remove other field codes 124 - for _, code := range []string{"%i", "%c", "%k"} { 125 - cmdline = strings.ReplaceAll(cmdline, code, "") 126 - } 127 - 128 - // Parse the command line 129 - parts := strings.Fields(cmdline) 130 - if len(parts) == 0 { 131 - fmt.Fprintf(os.Stderr, "Error: Empty command line for action %s\n", action.ID) 132 - return 133 - } 134 - 135 - // When running in Flatpak, wrap with flatpak-spawn --host 136 - if os.Getenv("FLATPAK_ID") != "" && !strings.HasPrefix(parts[0], "flatpak-spawn") { 137 - parts = append([]string{"flatpak-spawn", "--host"}, parts...) 138 - } 139 - 140 - // Execute the command 141 - cmd := exec.Command(parts[0], parts[1:]...) 142 - if err := cmd.Start(); err != nil { 82 + if err := launchCommand(action.Exec, url, b.AppInfo); err != nil { 143 83 fmt.Fprintf(os.Stderr, "Error launching browser action: %v\n", err) 144 - return 145 84 } 146 - 147 - // Clean up asynchronously 148 - go cmd.Wait() 149 85 }