[
  {
    "path": ".gitignore",
    "content": ".idea\n"
  },
  {
    "path": "darwin.go",
    "content": "// +build darwin\n\npackage wallpaper\n\nimport (\n\t\"os/exec\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n)\n\n// Get returns the path to the current wallpaper.\nfunc Get() (string, error) {\n\tstdout, err := exec.Command(\"osascript\", \"-e\", `tell application \"Finder\" to get POSIX path of (get desktop picture as alias)`).Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// is calling strings.TrimSpace() necessary?\n\treturn strings.TrimSpace(string(stdout)), nil\n}\n\n// SetFromFile uses AppleScript to tell Finder to set the desktop wallpaper to specified file.\nfunc SetFromFile(file string) error {\n\treturn exec.Command(\"osascript\", \"-e\", `tell application \"System Events\" to tell every desktop to set picture to `+strconv.Quote(file)).Run()\n}\n\n// SetMode does nothing on macOS.\nfunc SetMode(mode Mode) error {\n\treturn nil\n}\n\nfunc getCacheDir() (string, error) {\n\tusr, err := user.Current()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn filepath.Join(usr.HomeDir, \"Library\", \"Caches\"), nil\n}\n"
  },
  {
    "path": "example/main.go",
    "content": "package main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/reujab/wallpaper\"\n)\n\nfunc main() {\n\tbackground, err := wallpaper.Get()\n\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\tfmt.Println(\"Current wallpaper:\", background)\n\n\terr = wallpaper.SetFromFile(\"/usr/share/backgrounds/gnome/adwaita-day.jpg\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\n\terr = wallpaper.SetFromURL(\"https://i.imgur.com/pIwrYeM.jpg\")\n\tif err != nil {\n\t\tpanic(err)\n\t}\n}\n"
  },
  {
    "path": "gnome.go",
    "content": "package wallpaper\n\nimport (\n\t\"os/exec\"\n\t\"strings\"\n\n\tyaml \"gopkg.in/yaml.v2\"\n)\n\nfunc removeProtocol(input string) string {\n\tif len(input) >= 7 && input[:7] == \"file://\" {\n\t\treturn input[7:]\n\t}\n\treturn input\n}\n\nfunc parseDconf(command string, args ...string) (string, error) {\n\toutput, err := exec.Command(command, args...).Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t// unquote string\n\tvar unquoted string\n\t// the output is quoted with single quotes, which cannot be unquoted using strconv.Unquote, but it is valid yaml\n\terr = yaml.UnmarshalStrict(output, &unquoted)\n\tif err != nil {\n\t\treturn unquoted, err\n\t}\n\n\treturn removeProtocol(unquoted), nil\n}\n\nfunc isGNOMECompliant() bool {\n\treturn strings.Contains(Desktop, \"GNOME\") || Desktop == \"Unity\" || Desktop == \"Pantheon\"\n}\n\nfunc (mode Mode) getGNOMEString() string {\n\tswitch mode {\n\tcase Center:\n\t\treturn \"centered\"\n\tcase Crop:\n\t\treturn \"zoom\"\n\tcase Fit:\n\t\treturn \"scaled\"\n\tcase Span:\n\t\treturn \"spanned\"\n\tcase Stretch:\n\t\treturn \"stretched\"\n\tcase Tile:\n\t\treturn \"wallpaper\"\n\tdefault:\n\t\tpanic(\"invalid wallpaper mode\")\n\t}\n}\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/reujab/wallpaper\n\ngo 1.16\n\nrequire (\n\tgithub.com/smartystreets/goconvey v1.6.4 // indirect\n\tgolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a\n\tgopkg.in/ini.v1 v1.62.0\n\tgopkg.in/yaml.v2 v2.4.0\n)\n"
  },
  {
    "path": "go.sum",
    "content": "github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=\ngithub.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=\ngithub.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=\ngithub.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=\ngithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=\ngithub.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=\ngithub.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=\ngopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=\ngopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=\ngopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=\n"
  },
  {
    "path": "kde.go",
    "content": "//+build linux\n\npackage wallpaper\n\nimport (\n\t\"bufio\"\n\t\"errors\"\n\t\"os\"\n\t\"os/exec\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc getKDE() (string, error) {\n\tusr, err := user.Current()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfilename := filepath.Join(usr.HomeDir, \".config\", \"plasma-org.kde.plasma.desktop-appletsrc\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfile, err := os.Open(filename)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer file.Close()\n\n\tscanner := bufio.NewScanner(file)\n\tfor scanner.Scan() {\n\t\tline := scanner.Text()\n\t\tif len(line) >= 6 && line[:6] == \"Image=\" {\n\t\t\treturn strings.TrimSpace(removeProtocol(line[6:])), nil\n\t\t}\n\t}\n\tif scanner.Err() != nil {\n\t\treturn \"\", scanner.Err()\n\t}\n\n\terr = file.Close()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn \"\", errors.New(\"kde image not found\")\n}\n\nfunc setKDE(path string) error {\n\treturn evalKDE(`\n\t\tfor (const desktop of desktops()) {\n\t\t\tdesktop.currentConfigGroup = [\"Wallpaper\", \"org.kde.image\", \"General\"]\n\t\t\tdesktop.writeConfig(\"Image\", ` + strconv.Quote(\"file://\"+path) + `)\n\t\t}\n\t`)\n}\n\nfunc setKDEMode(mode Mode) error {\n\treturn evalKDE(`\n\t\tfor (const desktop of desktops()) {\n\t\t\tdesktop.currentConfigGroup = [\"Wallpaper\", \"org.kde.image\", \"General\"]\n\t\t\tdesktop.writeConfig(\"FillMode\", ` + mode.getKDEString() + `)\n\t\t}\n\t`)\n}\n\nfunc evalKDE(script string) error {\n\treturn exec.Command(\"qdbus\", \"org.kde.plasmashell\", \"/PlasmaShell\", \"org.kde.PlasmaShell.evaluateScript\", script).Run()\n}\n\nfunc (mode Mode) getKDEString() string {\n\tswitch mode {\n\tcase Center:\n\t\treturn \"6\"\n\tcase Crop:\n\t\treturn \"2\"\n\tcase Fit:\n\t\treturn \"1\"\n\tcase Span:\n\t\treturn \"2\"\n\tcase Stretch:\n\t\treturn \"0\"\n\tcase Tile:\n\t\treturn \"3\"\n\tdefault:\n\t\tpanic(\"invalid walllpaper mode\")\n\t}\n}\n"
  },
  {
    "path": "license",
    "content": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, compile, sell, or\ndistribute this software, either in source code form or as a compiled\nbinary, for any purpose, commercial or non-commercial, and by any\nmeans.\n\nIn jurisdictions that recognize copyright laws, the author or authors\nof this software dedicate any and all copyright interest in the\nsoftware to the public domain. We make this dedication for the benefit\nof the public at large and to the detriment of our heirs and\nsuccessors. We intend this dedication to be an overt act of\nrelinquishment in perpetuity of all present and future rights to this\nsoftware under copyright law.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\nOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\nARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nFor more information, please refer to <https://unlicense.org>\n"
  },
  {
    "path": "linux.go",
    "content": "// +build linux\n\npackage wallpaper\n\nimport (\n\t\"os/exec\"\n\t\"os/user\"\n\t\"path/filepath\"\n\t\"strconv\"\n)\n\n// Get returns the current wallpaper.\nfunc Get() (string, error) {\n\tif isGNOMECompliant() {\n\t\treturn parseDconf(\"gsettings\", \"get\", \"org.gnome.desktop.background\", \"picture-uri\")\n\t}\n\n\tswitch Desktop {\n\tcase \"KDE\":\n\t\treturn getKDE()\n\tcase \"X-Cinnamon\":\n\t\treturn parseDconf(\"dconf\", \"read\", \"/org/cinnamon/desktop/background/picture-uri\")\n\tcase \"MATE\":\n\t\treturn parseDconf(\"dconf\", \"read\", \"/org/mate/desktop/background/picture-filename\")\n\tcase \"XFCE\":\n\t\treturn getXFCE()\n\tcase \"LXDE\":\n\t\treturn getLXDE()\n\tcase \"Deepin\":\n\t\treturn parseDconf(\"dconf\", \"read\", \"/com/deepin/wrap/gnome/desktop/background/picture-uri\")\n\tdefault:\n\t\treturn \"\", ErrUnsupportedDE\n\t}\n}\n\n// SetFromFile sets wallpaper from a file path.\nfunc SetFromFile(file string) error {\n\tif isGNOMECompliant() {\n\t\treturn exec.Command(\"gsettings\", \"set\", \"org.gnome.desktop.background\", \"picture-uri\", strconv.Quote(\"file://\"+file)).Run()\n\t}\n\n\tswitch Desktop {\n\tcase \"KDE\":\n\t\treturn setKDE(file)\n\tcase \"X-Cinnamon\":\n\t\treturn exec.Command(\"dconf\", \"write\", \"/org/cinnamon/desktop/background/picture-uri\", strconv.Quote(\"file://\"+file)).Run()\n\tcase \"MATE\":\n\t\treturn exec.Command(\"dconf\", \"write\", \"/org/mate/desktop/background/picture-filename\", strconv.Quote(file)).Run()\n\tcase \"XFCE\":\n\t\treturn setXFCE(file)\n\tcase \"LXDE\":\n\t\treturn exec.Command(\"pcmanfm\", \"-w\", file).Run()\n\tcase \"Deepin\":\n\t\treturn exec.Command(\"dconf\", \"write\", \"/com/deepin/wrap/gnome/desktop/background/picture-uri\", strconv.Quote(\"file://\"+file)).Run()\n\tdefault:\n\t\terr := exec.Command(\"swaybg\", \"-i\", file).Start()\n\t\t// if the command completed successfully, return\n\t\tif err == nil {\n\t\t\treturn nil\n\t\t}\n\n\t\treturn exec.Command(\"feh\", \"-bg-fill\", file).Run()\n\t}\n}\n\n// SetMode sets the wallpaper mode.\nfunc SetMode(mode Mode) error {\n\tif isGNOMECompliant() {\n\t\treturn exec.Command(\"gsettings\", \"set\", \"org.gnome.desktop.background\", \"picture-options\", strconv.Quote(mode.getGNOMEString())).Run()\n\t}\n\n\tswitch Desktop {\n\tcase \"KDE\":\n\t\treturn setKDEMode(mode)\n\tcase \"X-Cinnamon\":\n\t\treturn exec.Command(\"dconf\", \"write\", \"/org/cinnamon/desktop/background/picture-options\", strconv.Quote(mode.getGNOMEString())).Run()\n\tcase \"MATE\":\n\t\treturn exec.Command(\"dconf\", \"write\", \"/org/mate/desktop/background/picture-options\", strconv.Quote(mode.getGNOMEString())).Run()\n\tcase \"XFCE\":\n\t\treturn setXFCEMode(mode)\n\tcase \"LXDE\":\n\t\treturn exec.Command(\"pcmanfm\", \"--wallpaper-mode\", mode.getLXDEString()).Run()\n\tcase \"Deepin\":\n\t\treturn exec.Command(\"dconf\", \"write\", \"/com/deepin/wrap/gnome/desktop/background/picture-options\", strconv.Quote(mode.getGNOMEString())).Run()\n\tdefault:\n\t\treturn ErrUnsupportedDE\n\t}\n}\n\nfunc getCacheDir() (string, error) {\n\tusr, err := user.Current()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn filepath.Join(usr.HomeDir, \".cache\"), nil\n}\n"
  },
  {
    "path": "lxde.go",
    "content": "package wallpaper\n\nimport (\n\t\"os/user\"\n\t\"path/filepath\"\n\n\tini \"gopkg.in/ini.v1\"\n)\n\nfunc getLXDE() (string, error) {\n\tusr, err := user.Current()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tif DesktopSession == \"\" {\n\t\tDesktopSession = \"LXDE\"\n\t}\n\n\tcfg, err := ini.Load(filepath.Join(usr.HomeDir, \".config/pcmanfm/\"+DesktopSession+\"/desktop-items-0.conf\"))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tkey, err := cfg.Section(\"*\").GetKey(\"wallpaper\")\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn key.String(), err\n}\n\nfunc (mode Mode) getLXDEString() string {\n\tswitch mode {\n\tcase Center:\n\t\treturn \"center\"\n\tcase Crop:\n\t\treturn \"crop\"\n\tcase Fit:\n\t\treturn \"fit\"\n\tcase Span:\n\t\treturn \"screen\"\n\tcase Stretch:\n\t\treturn \"stretch\"\n\tcase Tile:\n\t\treturn \"tile\"\n\tdefault:\n\t\tpanic(\"invalid wallpaper mode\")\n\t}\n}\n"
  },
  {
    "path": "main.go",
    "content": "package wallpaper\n\nimport (\n\t\"errors\"\n\t\"io\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n)\n\ntype Mode int\n\nconst (\n\tCenter Mode = iota\n\tCrop\n\tFit\n\tSpan\n\tStretch\n\tTile\n)\n\n// Desktop contains the current desktop environment on Linux.\n// Empty string on all other operating systems.\nvar Desktop = os.Getenv(\"XDG_CURRENT_DESKTOP\")\n\n// DesktopSession is used by LXDE on Linux.\nvar DesktopSession = os.Getenv(\"DESKTOP_SESSION\")\n\n// ErrUnsupportedDE is thrown when Desktop is not a supported desktop environment.\nvar ErrUnsupportedDE = errors.New(\"your desktop environment is not supported\")\n\nfunc downloadImage(url string) (string, error) {\n\tres, err := http.Get(url)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tdefer res.Body.Close()\n\tif res.StatusCode < 200 || res.StatusCode >= 300 {\n\t\treturn \"\", errors.New(\"non-200 status code\")\n\t}\n\n\tcacheDir, err := getCacheDir()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\tfile, err := os.Create(filepath.Join(cacheDir, \"wallpaper\"))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\t_, err = io.Copy(file, res.Body)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\terr = file.Close()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\treturn file.Name(), nil\n}\n\n// SetFromURL downloads the image to a cache directory and calls SetFromFile.\nfunc SetFromURL(url string) error {\n\tfile, err := downloadImage(url)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn SetFromFile(file)\n}\n"
  },
  {
    "path": "readme.md",
    "content": "# wallpaper [![godoc](https://godoc.org/github.com/reujab/wallpaper?status.svg)](https://godoc.org/github.com/reujab/wallpaper)\n\nA cross-platform (Linux, Windows, and macOS) Golang library for getting and setting the desktop background.\n\n## Installation\n\n```sh\ngo get github.com/reujab/wallpaper\n```\n\n## Example\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/reujab/wallpaper\"\n)\n\nfunc main() {\n\tbackground, err := wallpaper.Get()\n\tcheck(err)\n\tfmt.Println(\"Current wallpaper:\", background)\n\n\terr = wallpaper.SetFromFile(\"/usr/share/backgrounds/gnome/adwaita-day.jpg\")\n\tcheck(err)\n\n\terr = wallpaper.SetFromURL(\"https://i.imgur.com/pIwrYeM.jpg\")\n\tcheck(err)\n\n\terr = wallpaper.SetMode(wallpaper.Crop)\n\tcheck(err)\n}\n\n```\n\n## Supported desktops\n\n* Windows\n* macOS\n* GNOME\n* KDE\n* Cinnamon\n* Unity\n* Budgie\n* XFCE\n* LXDE\n* MATE\n* Deepin\n* Most Wayland compositors (set only, requires swaybg)\n* i3 (set only, requires feh)\n"
  },
  {
    "path": "windows.go",
    "content": "// +build windows\n\npackage wallpaper\n\nimport (\n\t\"golang.org/x/sys/windows/registry\"\n\t\"os\"\n\t\"strings\"\n\t\"syscall\"\n\t\"unicode/utf16\"\n\t\"unsafe\"\n)\n\n// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947.aspx\nconst (\n\tspiGetDeskWallpaper = 0x0073\n\tspiSetDeskWallpaper = 0x0014\n\n\tuiParam = 0x0000\n\n\tspifUpdateINIFile = 0x01\n\tspifSendChange    = 0x02\n)\n\n// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947.aspx\nvar (\n\tuser32               = syscall.NewLazyDLL(\"user32.dll\")\n\tsystemParametersInfo = user32.NewProc(\"SystemParametersInfoW\")\n)\n\n// Get returns the current wallpaper.\nfunc Get() (string, error) {\n\t// the maximum length of a windows path is 256 utf16 characters\n\tvar filename [256]uint16\n\tsystemParametersInfo.Call(\n\t\tuintptr(spiGetDeskWallpaper),\n\t\tuintptr(cap(filename)),\n\t\t// the memory address of the first byte of the array\n\t\tuintptr(unsafe.Pointer(&filename[0])),\n\t\tuintptr(0),\n\t)\n\treturn strings.Trim(string(utf16.Decode(filename[:])), \"\\x00\"), nil\n}\n\n// SetFromFile sets the wallpaper for the current user.\nfunc SetFromFile(filename string) error {\n\tfilenameUTF16, err := syscall.UTF16PtrFromString(filename)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tsystemParametersInfo.Call(\n\t\tuintptr(spiSetDeskWallpaper),\n\t\tuintptr(uiParam),\n\t\tuintptr(unsafe.Pointer(filenameUTF16)),\n\t\tuintptr(spifUpdateINIFile|spifSendChange),\n\t)\n\treturn nil\n}\n\n// SetMode sets the wallpaper mode.\nfunc SetMode(mode Mode) error {\n\tkey, _, err := registry.CreateKey(registry.CURRENT_USER, \"Control Panel\\\\Desktop\", registry.SET_VALUE)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer key.Close()\n\n\tvar tile string\n\tif mode == Tile {\n\t\ttile = \"1\"\n\t} else {\n\t\ttile = \"0\"\n\t}\n\terr = key.SetStringValue(\"TileWallpaper\", tile)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar style string\n\tswitch mode {\n\tcase Center, Tile:\n\t\tstyle = \"0\"\n\tcase Fit:\n\t\tstyle = \"6\"\n\tcase Span:\n\t\tstyle = \"22\"\n\tcase Stretch:\n\t\tstyle = \"2\"\n\tcase Crop:\n\t\tstyle = \"10\"\n\tdefault:\n\t\tpanic(\"invalid wallpaper mode\")\n\t}\n\terr = key.SetStringValue(\"WallpaperStyle\", style)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// updates wallpaper\n\tpath, err := Get()\n\tif err != nil {\n\t\treturn err\n\t}\n\n\treturn SetFromFile(path)\n}\n\nfunc getCacheDir() (string, error) {\n\treturn os.TempDir(), nil\n}\n"
  },
  {
    "path": "xfce.go",
    "content": "package wallpaper\n\nimport (\n\t\"os/exec\"\n\t\"path\"\n\t\"strings\"\n)\n\nfunc getXFCEProps(key string) ([]string, error) {\n\toutput, err := exec.Command(\"xfconf-query\", \"--channel\", \"xfce4-desktop\", \"--list\").Output()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tlines := strings.Split(strings.Trim(string(output), \"\\n\"), \"\\n\")\n\tvar desktops []string\n\n\tfor _, line := range lines {\n\t\tif path.Base(line) == key {\n\t\t\tdesktops = append(desktops, line)\n\t\t}\n\t}\n\n\treturn desktops, nil\n}\n\nfunc getXFCE() (string, error) {\n\tdesktops, err := getXFCEProps(\"last-image\")\n\tif err != nil || len(desktops) == 0 {\n\t\treturn \"\", err\n\t}\n\n\toutput, err := exec.Command(\"xfconf-query\", \"--channel\", \"xfce4-desktop\", \"--property\", desktops[0]).Output()\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\treturn strings.TrimSpace(string(output)), nil\n}\n\nfunc setXFCE(file string) error {\n\tdesktops, err := getXFCEProps(\"last-image\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor _, desktop := range desktops {\n\t\terr := exec.Command(\"xfconf-query\", \"--channel\", \"xfce4-desktop\", \"--property\", desktop, \"--set\", file).Run()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc setXFCEMode(mode Mode) error {\n\tstyles, err := getXFCEProps(\"image-style\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tfor _, style := range styles {\n\t\terr = exec.Command(\"xfconf-query\", \"--channel\", \"xfce4-desktop\", \"--property\", style, \"--set\", mode.getXFCEString()).Run()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (mode Mode) getXFCEString() string {\n\tswitch mode {\n\tcase Center:\n\t\treturn \"1\"\n\tcase Crop:\n\t\treturn \"5\"\n\tcase Fit:\n\t\treturn \"4\"\n\tcase Span:\n\t\treturn \"5\"\n\tcase Stretch:\n\t\treturn \"3\"\n\tcase Tile:\n\t\treturn \"2\"\n\tdefault:\n\t\tpanic(\"invalid wallpaper mode\")\n\t}\n}\n"
  }
]