···1010 "github.com/diamondburned/gotk4/pkg/gio/v2"
1111)
12121313-// Desktop file actions have IDs, names, and exec commands.
1413type DesktopAction struct {
1514 ID string // action ID (e.g., "new-private-window")
1615 Name string // display name (e.g., "New Private Window")
1716 Exec string // Exec command line for this action
1817}
19182020-// findDesktopFile locates a desktop file by ID using XDG Base Directory specification.
2121-// It searches in XDG_DATA_HOME and XDG_DATA_DIRS, plus Flatpak-specific locations.
1919+// Manually find desktop files according to XDG directories
2220func findDesktopFile(appID string) string {
2323- // Build list of data directories to search, following XDG spec
2421 var dataDirs []string
25222623 // XDG_DATA_HOME (default: ~/.local/share)
···4138 }
4239 }
43404444- // Add Flatpak-specific locations
4141+ // Flatpaks
4542 dataDirs = append(dataDirs, "/var/lib/flatpak/exports/share")
4643 if home := os.Getenv("HOME"); home != "" {
4744 dataDirs = append(dataDirs, home+"/.local/share/flatpak/exports/share")
···5855 return ""
5956}
60576161-/** ListDesktopActions returns available actions for an AppInfo by parsing its desktop file directly. For some reason, AppInfo does not expose actions. So we either call g_desktop_app_info_list_actions, which is not bound to Go, or parse it ourselves. I'd prefer to not use Cgo. **/
5858+/** ListDesktopActions returns available actions for an AppInfo by parsing its desktop file directly. For some reason, AppInfo does not expose actions. So we either call g_desktop_app_info_list_actions, which is not bound to Go, or parse it ourselves. I'd prefer to not use CGo. **/
6259func ListDesktopActions(appInfo *gio.AppInfo) []DesktopAction {
6360 if appInfo == nil {
6461 return nil
···8279}
83808481// parseDesktopFileActions parses a desktop file and extracts all actions.
8282+// Sketchier than what Glib gives us, but Glib doesn't give us this anyway.
8583// Desktop files are INI-format with sections like:
8684//
8785// [Desktop Entry]
···122120 if currentSection != "" && strings.HasPrefix(currentSection, "Desktop Action ") {
123121 if currentActionID != "" && currentActionName != "" && currentActionExec != "" {
124122 /** Only add if exec contains %u or %U (accepts URLs)
125125- This is commented because it breaks man Chromium-based browers completely, and even some Firefox-based brwosers allow passing URLs to actions unequiped to deal with them (e.g. LibreWolf). Looks less polished for the user, but works in more cases. **/
123123+ This is commented because it breaks many Chromium-based browers completely, and even some Firefox-based brwosers allow passing URLs to actions unequiped to deal with them (e.g. LibreWolf). Looks less polished for the user, but works in more cases. **/
126124127125 // if strings.Contains(currentActionExec, "%u") || strings.Contains(currentActionExec, "%U") {
128126 actions = append(actions, DesktopAction{
-1
src/dialog_about.go
···77 "github.com/diamondburned/gotk4/pkg/gtk/v4"
88)
991010-// showAboutDialog displays the application's about dialog.
1110func showAboutDialog(parent *adw.Window) {
1211 about := adw.NewAboutDialog()
1312
···77 "github.com/diamondburned/gotk4/pkg/gtk/v4"
88)
991010-// showDefaultBrowserPrompt displays a dialog asking to set Switchyard as default browser.
1110func showDefaultBrowserPrompt(parent gtk.Widgetter, cfg *Config, updateUI func()) {
1211 dialog := adw.NewAlertDialog(
1312 "Set as Default Browser?",
+2-6
src/dialog_helpers.go
···77 "github.com/diamondburned/gotk4/pkg/gtk/v4"
88)
991010-// dialogHeader creates a standard dialog header with cancel and action buttons.
1111-// The action button will have the "suggested-action" CSS class applied.
1210func dialogHeader(cancelLabel, actionLabel string, onCancel, onAction func()) (*adw.HeaderBar, *gtk.Button) {
1311 header := adw.NewHeaderBar()
1412 header.SetShowStartTitleButtons(false)
···8280 return dialog, content
8381}
84828585-// conditionTypeToIndex converts a condition type string to combo row index.
8383+// converts condition type string to combo row index.
8684func conditionTypeToIndex(condType string) uint {
8785 switch condType {
8886 case "domain":
···9896 }
9997}
10098101101-// indexToConditionType converts a combo row index to condition type string.
9999+// convert a combo row index to condition type string.
102100func indexToConditionType(index uint) string {
103101 switch index {
104102 case 0:
···114112 }
115113}
116114117117-// conditionTypeComboRow creates a standardized combo row for selecting condition types.
118115func conditionTypeComboRow(title string, initialType string) *adw.ComboRow {
119116 typeRow := adw.NewComboRow()
120117 typeRow.SetTitle(title)
···123120 return typeRow
124121}
125122126126-// getConditionTypeLabels returns the display labels for condition types in order.
127123func getConditionTypeLabels() []string {
128124 return []string{"Exact Domain", "URL Contains", "Wildcard", "Regex"}
129125}
-1
src/dialog_hidden_browsers.go
···77 "github.com/diamondburned/gotk4/pkg/gtk/v4"
88)
991010-// showHiddenBrowsersDialog displays a dialog for selecting which browsers to hide from the picker.
1110func showHiddenBrowsersDialog(parent *adw.Window, cfg *Config, browsers []*Browser) {
1211 dialog := adw.NewAlertDialog(
1312 "Hidden Browsers",
-1
src/dialog_rule_edit.go
···77 "github.com/diamondburned/gotk4/pkg/gtk/v4"
88)
991010-// showEditRuleDialog displays the edit rule dialog.
1110func showEditRuleDialog(parent *adw.Window, cfg *Config, rule *Rule, browsers []*Browser, rebuildRulesList func()) {
1211 // Ensure rules have at least one condition
1312 if len(rule.Conditions) == 0 {
-1
src/pattern.go
···77 "strings"
88)
991010-// matchesPattern checks if a URL matches a given pattern based on the pattern type
1110func matchesPattern(url, pattern, patternType string) bool {
1211 switch patternType {
1312 case "domain":
-2
src/picker_actions.go
···1313 "github.com/diamondburned/gotk4/pkg/gtk/v4"
1414)
15151616-// showBrowserActionsMenu shows a context menu with desktop file actions
1716func showBrowserActionsMenu(btn *gtk.Button, browser *Browser, url string) {
1817 actions := ListDesktopActions(browser.AppInfo)
1918 if len(actions) == 0 {
···4443 dialog.Present(parent)
4544}
46454747-// setupPickerActions sets up the action group for the picker window
4846func setupPickerActions(win *adw.Window, app *adw.Application, browsers []*Browser, url string, onClose func()) *gio.SimpleActionGroup {
4947 actionGroup := gio.NewSimpleActionGroup()
5048
-2
src/settings_rules.go
···118118 return id
119119 }
120120121121- // Function to rebuild the rules list UI
122121 var rebuildRulesList func()
123122124124- // Function to create a rule row
125123 createRuleRow := func(ruleIndex int) *adw.ActionRow {
126124 rule := &cfg.Rules[ruleIndex]
127125
-4
src/validation.go
···88 "strings"
99)
10101111-// validateConditions checks if all conditions have non-empty patterns and valid types
1211func validateConditions(conditions []Condition) bool {
1312 validTypes := map[string]bool{
1413 "domain": true,
···3433 return true
3534}
36353737-// validateDomainPattern checks if a domain pattern is valid (no wildcards allowed).
3836// Domain patterns should be exact hostnames like "example.com" or "api.github.com".
3937func validateDomainPattern(pattern string) error {
4038 if pattern == "" {
···7270 return nil
7371}
74727575-// validateGlobPattern checks if a glob (wildcard) pattern is valid.
7673// Glob patterns can contain * wildcards for matching multiple characters.
7774func validateGlobPattern(pattern string) error {
7875 if pattern == "" {
···108105 return nil
109106}
110107111111-// validateConditionPattern checks if a condition's pattern is valid for its type.
112108// Returns an error with a descriptive message if invalid, nil if valid.
113109func validateConditionPattern(condType, pattern string) error {
114110 if pattern == "" {
-1
src/window_picker.go
···1111 "github.com/diamondburned/gotk4/pkg/pango"
1212)
13131414-// showPickerWindow displays the browser picker window
1514func showPickerWindow(app *adw.Application, url string, browsers []*Browser, cfg *Config) {
16151716 // Filter hidden_browsers from the list