mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-14 16:22:46 -04:00
018795125e
- Adds "DMS Opener" as an option (dms-open.desktop) - Add mime type GO utils - Add rememberance to App Picker modal
227 lines
4.8 KiB
Go
227 lines
4.8 KiB
Go
package desktop
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/utils"
|
|
)
|
|
|
|
var mimeappsWriteMu sync.Mutex
|
|
|
|
const (
|
|
groupDefaults = "Default Applications"
|
|
groupAdded = "Added Associations"
|
|
groupRemoved = "Removed Associations"
|
|
)
|
|
|
|
type MimeAssociations struct {
|
|
Defaults map[string]string
|
|
Added map[string][]string
|
|
Removed map[string][]string
|
|
}
|
|
|
|
func newAssociations() *MimeAssociations {
|
|
return &MimeAssociations{
|
|
Defaults: make(map[string]string),
|
|
Added: make(map[string][]string),
|
|
Removed: make(map[string][]string),
|
|
}
|
|
}
|
|
|
|
func mimeappsSearchPaths() []string {
|
|
var paths []string
|
|
seen := make(map[string]bool)
|
|
|
|
add := func(p string) {
|
|
if p == "" || seen[p] {
|
|
return
|
|
}
|
|
seen[p] = true
|
|
paths = append(paths, p)
|
|
}
|
|
|
|
add(filepath.Join(utils.XDGConfigHome(), "mimeapps.list"))
|
|
|
|
if env := os.Getenv("XDG_CONFIG_DIRS"); env != "" {
|
|
for d := range strings.SplitSeq(env, ":") {
|
|
add(filepath.Join(strings.TrimSpace(d), "mimeapps.list"))
|
|
}
|
|
} else {
|
|
add("/etc/xdg/mimeapps.list")
|
|
}
|
|
|
|
add(filepath.Join(utils.XDGDataHome(), "applications", "mimeapps.list"))
|
|
|
|
if env := os.Getenv("XDG_DATA_DIRS"); env != "" {
|
|
for d := range strings.SplitSeq(env, ":") {
|
|
add(filepath.Join(strings.TrimSpace(d), "applications", "mimeapps.list"))
|
|
}
|
|
} else {
|
|
add("/usr/local/share/applications/mimeapps.list")
|
|
add("/usr/share/applications/mimeapps.list")
|
|
}
|
|
|
|
return paths
|
|
}
|
|
|
|
func mimeappsWritePath() string {
|
|
return filepath.Join(utils.XDGConfigHome(), "mimeapps.list")
|
|
}
|
|
|
|
func readAssociations(path string) (*MimeAssociations, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
groups := parseGroups(data)
|
|
assoc := newAssociations()
|
|
|
|
if g := groups[groupDefaults]; g != nil {
|
|
for mime, val := range g.keys {
|
|
parts := splitList(val)
|
|
if len(parts) > 0 {
|
|
assoc.Defaults[mime] = parts[0]
|
|
}
|
|
}
|
|
}
|
|
|
|
if g := groups[groupAdded]; g != nil {
|
|
for mime, val := range g.keys {
|
|
assoc.Added[mime] = splitList(val)
|
|
}
|
|
}
|
|
|
|
if g := groups[groupRemoved]; g != nil {
|
|
for mime, val := range g.keys {
|
|
assoc.Removed[mime] = splitList(val)
|
|
}
|
|
}
|
|
|
|
return assoc, nil
|
|
}
|
|
|
|
func mergedAssociations() *MimeAssociations {
|
|
merged := newAssociations()
|
|
|
|
for _, path := range mimeappsSearchPaths() {
|
|
assoc, err := readAssociations(path)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
for mime, app := range assoc.Defaults {
|
|
if _, ok := merged.Defaults[mime]; !ok {
|
|
merged.Defaults[mime] = app
|
|
}
|
|
}
|
|
for mime, apps := range assoc.Added {
|
|
merged.Added[mime] = append(merged.Added[mime], apps...)
|
|
}
|
|
for mime, apps := range assoc.Removed {
|
|
merged.Removed[mime] = append(merged.Removed[mime], apps...)
|
|
}
|
|
}
|
|
|
|
return merged
|
|
}
|
|
|
|
func writeUserMimeapps(update func(*MimeAssociations)) error {
|
|
mimeappsWriteMu.Lock()
|
|
defer mimeappsWriteMu.Unlock()
|
|
|
|
path := mimeappsWritePath()
|
|
|
|
assoc, err := readAssociations(path)
|
|
if err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
assoc = newAssociations()
|
|
}
|
|
|
|
update(assoc)
|
|
|
|
var buf bytes.Buffer
|
|
w := bufio.NewWriter(&buf)
|
|
|
|
writeSection := func(name string, entries map[string]string) {
|
|
fmt.Fprintf(w, "[%s]\n", name)
|
|
keys := make([]string, 0, len(entries))
|
|
for k := range entries {
|
|
keys = append(keys, k)
|
|
}
|
|
sort.Strings(keys)
|
|
for _, k := range keys {
|
|
fmt.Fprintf(w, "%s=%s\n", k, entries[k])
|
|
}
|
|
fmt.Fprintln(w)
|
|
}
|
|
|
|
flatten := func(m map[string][]string) map[string]string {
|
|
out := make(map[string]string, len(m))
|
|
for k, list := range m {
|
|
out[k] = strings.Join(list, ";") + ";"
|
|
}
|
|
return out
|
|
}
|
|
|
|
writeSection(groupDefaults, assoc.Defaults)
|
|
writeSection(groupAdded, flatten(assoc.Added))
|
|
writeSection(groupRemoved, flatten(assoc.Removed))
|
|
|
|
if err := w.Flush(); err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
return err
|
|
}
|
|
return os.WriteFile(path, buf.Bytes(), 0o644)
|
|
}
|
|
|
|
func setDefaultAssociation(mimeType, desktopID string) error {
|
|
return setDefaultAssociations([]string{mimeType}, desktopID)
|
|
}
|
|
|
|
func setDefaultAssociations(mimeTypes []string, desktopID string) error {
|
|
if !strings.HasSuffix(desktopID, ".desktop") {
|
|
desktopID += ".desktop"
|
|
}
|
|
return writeUserMimeapps(func(assoc *MimeAssociations) {
|
|
for _, mimeType := range mimeTypes {
|
|
if mimeType == "" {
|
|
continue
|
|
}
|
|
assoc.Defaults[mimeType] = desktopID
|
|
existing := assoc.Added[mimeType]
|
|
if !slices.Contains(existing, desktopID) {
|
|
assoc.Added[mimeType] = append(existing, desktopID)
|
|
}
|
|
removed, ok := assoc.Removed[mimeType]
|
|
if !ok {
|
|
continue
|
|
}
|
|
filtered := removed[:0]
|
|
for _, id := range removed {
|
|
if id != desktopID {
|
|
filtered = append(filtered, id)
|
|
}
|
|
}
|
|
switch {
|
|
case len(filtered) == 0:
|
|
delete(assoc.Removed, mimeType)
|
|
default:
|
|
assoc.Removed[mimeType] = filtered
|
|
}
|
|
}
|
|
})
|
|
}
|