package main import ( "bufio" "os" "path/filepath" "strconv" "strings" ) // Reading the configuration again (novox/hq ADR 0262). A running dunst reads its files only when it // starts or is told to reload; the node-engine tells it through the account's dunst.service (its // ExecReload is `dunstctl reload`) whenever the mesh rewrites dunstrc, and dunst_reload tells it now. // A reload keeps the notifications on screen and in the history; a restart would lose them. // Globals are the [global] font and width the configuration files set, and which file set each. type Globals struct { Font string `json:"font,omitempty"` FontSize int `json:"font_size,omitempty"` FontFrom string `json:"font_from,omitempty"` Width string `json:"width,omitempty"` WidthFrom string `json:"width_from,omitempty"` } // ReloadResult is what dunst_reload answers. type ReloadResult struct { Reloaded bool `json:"reloaded"` Files []string `json:"files"` Globals Displayed int `json:"displayed"` Note string `json:"note"` } // Reload tells the running dunst to read its configuration again, shows it still answers, and says // the font and width the files it read set. func Reload() (ReloadResult, error) { // No files named: dunst reads its own search path, dunstrc and then dunstrc.d, as at its start. if _, err := dunstctl("reload"); err != nil { return ReloadResult{}, err } shown, err := dunstctl("count", "displayed") if err != nil { return ReloadResult{}, err } displayed, _ := strconv.Atoi(strings.TrimSpace(shown)) files := configFiles(filepath.Join(operatorHome(), ".config", "dunst")) return ReloadResult{ Reloaded: true, Files: files, Globals: globalsOf(files), Displayed: displayed, Note: "dunst read these files again and still answers. dunst does not answer its settings over " + "the bus, so font and width are what the files it read set (the last file that sets one wins); " + "the next notification is drawn with them", }, nil } // globalsOf reads the [global] font and width from the files in the order dunst reads them; a later // file outranks an earlier one, and a rule's own font is the rule's, not the global one. func globalsOf(files []string) Globals { var g Globals for _, path := range files { f, err := os.Open(path) if err != nil { continue } section := "" lines := bufio.NewScanner(f) for lines.Scan() { line := strings.TrimSpace(lines.Text()) if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") { continue } if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") { section = strings.TrimSpace(line[1 : len(line)-1]) continue } key, value, ok := strings.Cut(line, "=") if !ok || section != "global" { continue } value = strings.Trim(strings.TrimSpace(value), `"`) switch strings.TrimSpace(key) { case "font": g.Font, g.FontFrom, g.FontSize = value, path, 0 if fields := strings.Fields(value); len(fields) > 0 { if n, err := strconv.Atoi(fields[len(fields)-1]); err == nil { g.FontSize = n } } case "width": g.Width, g.WidthFrom = value, path } } f.Close() } return g }