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

Configure Feed

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

tree-wide: replace 'picker' with 'launcher'

Aly Raffauf (Jan 23, 2026, 10:01 PM EST) 9d3f77e5 8533ed31

+24 -25
+2 -2
README.md
··· 7 7 </div> 8 8 9 9 <p align="center"> 10 - <img src="docs/images/switchyard-picker.png" alt="Switchyard Picker" width="600"> 10 + <img src="docs/images/switchyard-picker.png" alt="Switchyard Launcher" width="600"> 11 11 </p> 12 12 13 13 <p align="center"> ··· 20 20 - **Multi-condition rules**: Combine multiple conditions with AND/OR logic for precise control. 21 21 - **Multiple pattern types**: Exact Domain, URL Contains, Wildcard, and Regex matching. 22 22 - **Custom URI scheme**: Create links that specify browser preferences directly with `switchyard://` URLs. 23 - - **Quick browser picker**: When no rule matches, quickly select a browser with keyboard or mouse. 23 + - **Quick browser launcher**: When no rule matches, quickly select a browser with keyboard or mouse. 24 24 - **Keyboard shortcuts**: Press Ctrl+1-9 to instantly select a browser. 25 25 - **Lightweight**: Runs only when needed, no background processes. 26 26 - **GTK4 + libadwaita**: Native GNOME look and feel.
+1 -1
data/io.github.alyraffauf.Switchyard.metainfo.xml
··· 64 64 <p>This release comes with the following improvements:</p> 65 65 <ul> 66 66 <li>Added switchyard:// custom URI scheme.</li> 67 - <li>Fixed crashes for hamburger menu in browser picker.</li> 67 + <li>Fixed crashes for hamburger menu in browser launcher.</li> 68 68 </ul> 69 69 </description> 70 70 </release>
+2 -2
docs/Configuration.md
··· 67 67 68 68 ## Settings 69 69 70 - - **prompt_on_click**: Show picker when no rule matches (default: true). 71 - - **favorite_browser**: Favorite browser that always appears first in picker and is used as fallback when picker is disabled. 70 + - **prompt_on_click**: Show launcher when no rule matches (default: true). 71 + - **favorite_browser**: Favorite browser that always appears first in launcher and is used as fallback when launcher is disabled. 72 72 - **check_default_browser**: Prompt to set Switchyard as system default browser on startup (default: true). 73 73 74 74 ## Rules
+1 -1
src/dialog_hidden_browsers.go
··· 10 10 func showHiddenBrowsersDialog(parent *adw.Window, cfg *Config, browsers []*Browser) { 11 11 dialog := adw.NewAlertDialog( 12 12 "Hidden Browsers", 13 - "Select browsers to hide from the picker window. Hidden browsers won't appear in the picker, but can still be used in rules and settings.", 13 + "You can still use hidden browsers in rules.", 14 14 ) 15 15 16 16 // Create a scrolled window for the browser list
+1 -1
src/dialog_rule_common.go
··· 124 124 actionGroup.SetDescription("Select which browser opens matching URLs") 125 125 126 126 alwaysAskRow = adw.NewSwitchRow() 127 - alwaysAskRow.SetTitle("Always show picker") 127 + alwaysAskRow.SetTitle("Always show launcher") 128 128 alwaysAskRow.SetSubtitle("Ask which browser to use each time") 129 129 if initialRule != nil { 130 130 alwaysAskRow.SetActive(initialRule.AlwaysAsk)
+4 -5
src/main.go
··· 117 117 return 118 118 } 119 119 } 120 - // No preferred browser found - show picker 121 - showPickerWindow(app, sanitized, browsers, cfg) 120 + // No preferred browser found - show launcher 121 + showLauncherWindow(app, sanitized, browsers, cfg) 122 122 return 123 123 } 124 124 ··· 135 135 if matched { 136 136 // Check if rule has AlwaysAsk enabled 137 137 if alwaysAsk { 138 - showPickerWindow(app, urlStr, browsers, cfg) 138 + showLauncherWindow(app, urlStr, browsers, cfg) 139 139 return 140 140 } 141 141 ··· 156 156 } 157 157 } 158 158 159 - // Show picker 160 - showPickerWindow(app, urlStr, browsers, cfg) 159 + showLauncherWindow(app, urlStr, browsers, cfg) 161 160 }
+2 -2
src/picker_actions.go src/launcher_actions.go
··· 33 33 func showShortcutsDialog(parent *adw.Window) { 34 34 dialog := adw.NewAlertDialog( 35 35 "Keyboard Shortcuts", 36 - "Ctrl+1 through Ctrl+9: Select browser 1-9\nEsc: Close picker window", 36 + "Ctrl+1 through Ctrl+9: Select browser 1-9\nEsc: Close launcher", 37 37 ) 38 38 39 39 dialog.AddResponse("ok", "OK") ··· 43 43 dialog.Present(parent) 44 44 } 45 45 46 - func setupPickerActions(win *adw.Window, app *adw.Application, browsers []*Browser, url string, onClose func()) *gio.SimpleActionGroup { 46 + func setupLauncherActions(win *adw.Window, app *adw.Application, browsers []*Browser, url string, onClose func()) *gio.SimpleActionGroup { 47 47 actionGroup := gio.NewSimpleActionGroup() 48 48 49 49 settingsAction := gio.NewSimpleAction("settings", nil)
+7 -7
src/settings_appearance.go
··· 23 23 24 24 content.Append(appearanceGroup) 25 25 26 - // Picker Window section 27 - pickerGroup := adw.NewPreferencesGroup() 28 - pickerGroup.SetTitle("Picker Window") 26 + // Launcher section 27 + launcherGroup := adw.NewPreferencesGroup() 28 + launcherGroup.SetTitle("Launcher") 29 29 30 30 showNamesRow := adw.NewSwitchRow() 31 31 showNamesRow.SetTitle("Show browser names") 32 32 showNamesRow.SetSubtitle("Show browser names below icons") 33 33 showNamesRow.SetActive(cfg.ShowAppNames) 34 - pickerGroup.Add(showNamesRow) 34 + launcherGroup.Add(showNamesRow) 35 35 36 36 // Hidden browsers row 37 37 hiddenBrowsersRow := adw.NewActionRow() 38 38 hiddenBrowsersRow.SetTitle("Hidden browsers") 39 - hiddenBrowsersRow.SetSubtitle("Choose which browsers to hide from the picker") 39 + hiddenBrowsersRow.SetSubtitle("Hide browsers you don't use") 40 40 hiddenBrowsersRow.SetActivatable(true) 41 41 42 42 chevron := gtk.NewImageFromIconName("go-next-symbolic") ··· 46 46 showHiddenBrowsersDialog(win, cfg, browsers) 47 47 }) 48 48 49 - pickerGroup.Add(hiddenBrowsersRow) 49 + launcherGroup.Add(hiddenBrowsersRow) 50 50 51 - content.Append(pickerGroup) 51 + content.Append(launcherGroup) 52 52 53 53 // Connect change handlers 54 54 forceDarkRow.Connect("notify::active", func() {
+2 -2
src/settings_behavior.go
··· 21 21 behaviorGroup.Add(checkDefaultRow) 22 22 23 23 promptRow := adw.NewSwitchRow() 24 - promptRow.SetTitle("Show picker when no rule matches") 24 + promptRow.SetTitle("Show launcher when no rule matches") 25 25 promptRow.SetSubtitle("Let you choose a browser for unmatched URLs") 26 26 promptRow.SetActive(cfg.PromptOnClick) 27 27 behaviorGroup.Add(promptRow) ··· 36 36 37 37 defaultRow := adw.NewComboRow() 38 38 defaultRow.SetTitle("Favorite browser") 39 - defaultRow.SetSubtitle("Appears first in picker and opens when picker is disabled") 39 + defaultRow.SetSubtitle("Shown first in launcher; used for all links when launcher is disabled") 40 40 defaultRow.SetModel(browserList) 41 41 42 42 // Set initial selection
+2 -2
src/window_picker.go src/window_launcher.go
··· 11 11 "github.com/diamondburned/gotk4/pkg/pango" 12 12 ) 13 13 14 - func showPickerWindow(app *adw.Application, url string, browsers []*Browser, cfg *Config) { 14 + func showLauncherWindow(app *adw.Application, url string, browsers []*Browser, cfg *Config) { 15 15 16 16 // Filter hidden_browsers from the list 17 17 hiddenSet := make(map[string]bool) ··· 243 243 win.AddController(keyController) 244 244 245 245 // Set up action handlers 246 - actionGroup := setupPickerActions(win, app, filteredBrowsers, url, func() { win.Close() }) 246 + actionGroup := setupLauncherActions(win, app, filteredBrowsers, url, func() { win.Close() }) 247 247 win.InsertActionGroup("win", actionGroup) 248 248 249 249 win.Present()