1package wallutils 2 3import ( 4 "errors" 5 "fmt" 6 "os" 7 "strings" 8) 9 10// WM is an interface with the functions that needs to be implemented for adding support for setting the wallpaper for a new WM or DE 11type WM interface { 12 Name() string 13 ExecutablesExists() bool 14 Running() bool 15 SetWallpaper(string) error 16 SetVerbose(bool) 17 SetMode(string) 18} 19 20// Wallpaper represents an image file that is part of a wallpaper collection (in a directory with several resolutions of the same image, for example) 21type Wallpaper struct { 22 CollectionName string // the name of the directory containing this wallpaper, if it's not "pixmaps", "images" or "contents". May use the parent of the parent. 23 Path string // full path to the image filename 24 Width uint // width of the image 25 Height uint // height of the image 26 PartOfCollection bool // likely to be part of a wallpaper collection 27} 28 29// All backends should support these modes, if possible: stretch, fill, scale, tile, center 30const defaultMode = "stretch" 31 32// SetWallpaperCustom will set the given image filename as the wallpaper, 33// regardless of which display server, window manager or desktop environment is in use. 34func SetWallpaperCustom(imageFilename, mode string, verbose bool) error { 35 if !exists(imageFilename) { 36 return fmt.Errorf("no such file: %s", imageFilename) 37 } 38 var lastErr error 39 // Loop through all available WM structs 40 for _, wm := range WMs { 41 if wm.Running() && wm.ExecutablesExists() { 42 if verbose { 43 fmt.Printf("Using the %s backend.\n", wm.Name()) 44 } 45 wm.SetVerbose(verbose) 46 if mode != "" && mode != defaultMode { 47 wm.SetMode(mode) 48 } 49 if err := wm.SetWallpaper(imageFilename); err != nil { 50 lastErr = err 51 switch wm.Name() { 52 case "Weston": 53 // If the current windowmanager is Weston, no method is currently available 54 return err 55 default: 56 if verbose { 57 fmt.Fprintf(os.Stderr, "failed: %v\n", err) 58 } 59 // If the wallpaper mode is wrong, don't try the next backend, but return the error 60 if strings.Contains(err.Error(), "invalid desktop wallpaper mode") { 61 return err 62 } 63 // Try the next one 64 continue 65 } 66 } else { 67 return nil 68 } 69 } 70 } 71 if lastErr != nil { 72 return fmt.Errorf("found no working method for setting the desktop wallpaper:\n%v", lastErr) 73 } 74 return errors.New("found no working method for setting the desktop wallpaper") 75 76} 77 78// SetWallpaperVerbose will set the desktop wallpaper, for any supported 79// windowmanager. The fallback is to use `feh`. The wallpaper mode is "fill". 80func SetWallpaperVerbose(imageFilename string, verbose bool) error { 81 return SetWallpaperCustom(imageFilename, defaultMode, verbose) 82} 83 84// SetWallpaper will set the desktop wallpaper, for any supported 85// windowmanager. The fallback is to use `feh`. The wallpaper mode is "fill". 86func SetWallpaper(imageFilename string) error { 87 return SetWallpaperCustom(imageFilename, defaultMode, false) 88} 89 90// Res returns the wallpaper resolution as a Res struct 91func (wp *Wallpaper) Res() *Res { 92 return NewRes(wp.Width, wp.Height) 93} 94 95// String returns a string with information about the wallpaper: 96// - if it's part of a wallpaper collection or not 97// - width 98// - height 99// - collection name 100// - path 101func (wp *Wallpaper) String() string { 102 star := " " 103 if wp.PartOfCollection { 104 star = "*" 105 } 106 return fmt.Sprintf("(%s) %dx%d\t%16s\t%s", star, wp.Width, wp.Height, wp.CollectionName, wp.Path) 107} 108