Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
xyproto committed Feb 7, 2019
1 parent ad26921 commit 3a37f23
Show file tree
Hide file tree
Showing 41 changed files with 1,948 additions and 13 deletions.
18 changes: 6 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib

# Test binary, build with `go test -c`
*.test

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
cmd/setrandom/setrandom
cmd/setwallpaper/setwallpaper
cmd/lsmon/lsmon
cmd/wayinfo/wayinfo
cmd/xinfo/xinfo
cmd/getdpi/getdpi
13 changes: 13 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
language: go

addons:
apt:
packages:
- build-essential
- libx11-dev
- libxcursor-dev
- libwayland-dev

go:
- "1.11"
- tip
24 changes: 24 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,27 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

---

Copyright for portions of the Wayland-related parts of Wallpaper2 are held by
Philipp Brüschweiler, 2012 as part of weston. All other copyright for
Wallpaper2 are held by Alexander F. Rødseth, 2019.

Permission to use, copy, modify, distribute, and sell this software and
its documentation for any purpose is hereby granted without fee, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of the copyright holders not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission. The copyright holders make
no representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied warranty.

THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# monitor
Go package for dealing with monitors, resolutions and setting wallpapers, under both X and Wayland

Go package for dealing with monitors, resolutions and setting wallpapers, under both X and Wayland.
56 changes: 56 additions & 0 deletions cinnamon.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package monitor

// Cinnamon windowmanager detector
type Cinnamon struct {
mode string // none | wallpaper | centered | scaled | stretched | zoom | spanned, scaled is the default
hasDconf bool
hasGsettings bool
hasChecked bool
}

func (s *Cinnamon) Name() string {
return "Cinnamon"
}

func (s *Cinnamon) ExecutablesExists() bool {
s.hasDconf = which("dconf") != ""
s.hasGsettings = which("gsettings") != ""
s.hasChecked = true
return s.hasDconf || s.hasGsettings
}

func (s *Cinnamon) Running() bool {
// TODO: To test
return (containsE("GDMSESSION", "cinnamon") || containsE("XDG_SESSION_DESKTOP", "cinnamon") || containsE("XDG_CURRENT_DESKTOP", "cinnamon"))
}

func (s *Cinnamon) SetMode(mode string) {
s.mode = mode
}

// SetWallpaper sets the desktop wallpaper, given an image filename.
// The image must exist and be readable.
func (s *Cinnamon) SetWallpaper(imageFilename string) error {
// Check if dconf or gsettings are there, if we haven't already checked
if !s.hasChecked {
s.ExecutablesExists()
}
// Set the desktop wallpaper picture mode
mode := defaultMode
if s.mode != "" {
mode = s.mode
}
// Change the background with either dconf or gsettings
if s.hasDconf {
// use dconf
if err := run("dconf write /org/cinnamon/desktop/background/picture-filename \"'" + imageFilename + "'\""); err != nil {
return err
}
return run("dconf write /org/cinnamon/desktop/background/picture-options \"'" + mode + "'\"")
}
// use gsettings
if err := run("gsettings set org.cinnamon.background picture-filename '" + imageFilename + "'"); err != nil {
return err
}
return run("gsettings set org.cinnamon.background picture-options '" + mode + "'")
}
43 changes: 43 additions & 0 deletions closest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package monitor

import (
"os"
)

// Exists checks if the given filename exists in the current directory
// (or if an absolute path exists)
func Exists(filename string) bool {
_, err := os.Stat(filename)
return !os.IsNotExist(err)
}

// Closest takes a list of filenames on the form "*_WIDTHxHEIGHT.ext".
// WIDTH and HEIGHT are numbers. Closest returns the filename that is closest
// to the average monitor resolution. Any filenames not following the pattern
// will result in an error being returned.
func Closest(filenames []string) (string, error) {
avgRes, err := AverageResolution()
if err != nil {
return "", err
}
// map: (distance to average resolution) => (filename)
d := make(map[int]string)
var dist int
var minDist int
var minDistSet bool
for _, filename := range filenames {
res, err := FilenameToRes(filename)
if err != nil {
return "", err
}
dist = Distance(avgRes, res)
if dist < minDist || !minDistSet {
minDist = dist
minDistSet = true
}
//fmt.Printf("FILENAME %s HAS DISTANCE %d TO AVERAGE RESOLUTION %s\n", filename, dist, avgRes)
d[dist] = filename
}
// ok, have a map, now find the filename of the smallest distance
return d[minDist], nil
}
29 changes: 29 additions & 0 deletions closest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package monitor

import (
"fmt"
"testing"
)

func TestClosest(t *testing.T) {
filenames := []string{"hello_1024x768.jpg", "hello_1600x1200.jpg", "hello_320x200.jpg"}
fmt.Println(filenames)

resolutions, err := ExtractResolutions(filenames)
if err != nil {
t.Error(err)
}
fmt.Println("Resolutions extracted from slice of filenames:", resolutions)

avgRes, err := AverageResolution()
if err != nil {
t.Error(err)
}
fmt.Println("Average resolution for all connected monitors:", avgRes)

filename, err := Closest(filenames)
if err != nil {
t.Error(err)
}
fmt.Println("Filename closest to the average resolution:", filename)
}
31 changes: 31 additions & 0 deletions cmd/getdpi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# getdpi

Tool for retrieving the average DPI across all monitors, regardless of if X or Wayland is in use.

## Building getdpi

go build

## Usage

Retreive the average DPI as a pair of numbers (ie. `96x96`):

getdpi -b

Retreive the average DPI as a single number (ie. `96`):

getdpi

Version information:

getdpi --version

## Listing DPI per monitor

The `lsmon` utility in the [monitor](https://github.com/xyproto/monitor) package supports listing monitor resolutions and DPI with the `-dpi` flag.

## General Info

* Version: 1.2.0
* License: MIT
* Author: Alexander F. Rødseth &lt;[email protected]&gt;
39 changes: 39 additions & 0 deletions cmd/getdpi/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"fmt"
"os"

"github.com/xyproto/monitor"
)

const versionString = "1.2.0"

func main() {
// Retrieve a slice of Monitor structs, or exit with an error
monitors, err := monitor.Detect()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
// Output the average DPI
DPIw, DPIh := uint(0), uint(0)
for _, monitor := range monitors {
DPIw += monitor.DPIw
DPIh += monitor.DPIh
}
DPIw /= uint(len(monitors))
DPIh /= uint(len(monitors))

// Check if -b is given (for outputting both numbers)
if len(os.Args) > 1 && os.Args[1] == "-b" {
fmt.Printf("%dx%d\n", DPIw, DPIh)
return
} else if len(os.Args) > 1 && os.Args[1] == "--version" {
fmt.Println(versionString)
return
}

// Output a single number
fmt.Println(DPIw)
}
3 changes: 3 additions & 0 deletions cmd/lsmon/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
List all monitors, with resolutions

Use the `-dpi` flag to also list the DPI per monitor.
25 changes: 25 additions & 0 deletions cmd/lsmon/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"fmt"
"os"

"github.com/xyproto/monitor"
)

func main() {
// Retrieve a slice of Monitor structs, or exit with an error
monitors, err := monitor.Detect()
if err != nil {
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
// For every monitor, output the ID, width and height
for _, monitor := range monitors {
if len(os.Args) > 1 && os.Args[1] == "-dpi" {
fmt.Printf("%d: %dx%d (DPI: %dx%d)\n", monitor.ID, monitor.Width, monitor.Height, monitor.DPIw, monitor.DPIh)
} else {
fmt.Printf("%d: %dx%d\n", monitor.ID, monitor.Width, monitor.Height)
}
}
}
3 changes: 3 additions & 0 deletions cmd/setrandom/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This executable will change the desktop wallpaper to a random .png image from `/usr/share/pixmaps`.

Don't run the executable if you don't want to change the desktop wallpaper!
53 changes: 53 additions & 0 deletions cmd/setrandom/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package main

import (
"bufio"
"fmt"
"math/rand"
"os"
"path/filepath"
"strings"
"time"

"github.com/xyproto/monitor"
)

const versionString = "Random Wallpaper Changer 1.0.0"

func init() {
rand.Seed(time.Now().UTC().UnixNano())
}

func main() {
fmt.Println(versionString)
reader := bufio.NewReader(os.Stdin)
fmt.Print("Please type \"yes\" if you want to change the desktop wallpaper to a random image: ")
text, err := reader.ReadString('\n')
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if strings.TrimSpace(text) != "yes" {
fmt.Println("OK, made no changes.")
os.Exit(0)
}

matches, err := filepath.Glob("/usr/share/pixmaps/*.png")
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
imageFilename := matches[rand.Int()%len(matches)]
if absImageFilename, err := filepath.Abs(imageFilename); err == nil {
imageFilename = absImageFilename
}
if _, err := os.Stat(imageFilename); os.IsNotExist(err) {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Println("Setting background image to: " + imageFilename)
if err := monitor.SetWallpaper(imageFilename); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
3 changes: 3 additions & 0 deletions cmd/setwallpaper/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
`setwallpaper` aims to be able to change the desktop wallpaper, for any windowmanager.

The first argument is the image to use.
38 changes: 38 additions & 0 deletions cmd/setwallpaper/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package main

import (
"fmt"
"os"
"path/filepath"

"github.com/xyproto/monitor"
)

const versionString = "setwallpaper"

func main() {
if len(os.Args) < 2 {
fmt.Fprintln(os.Stderr, versionString+"\n\nNeeds an image file as the first argument.")
os.Exit(1)
}
imageFilename := os.Args[1]

// Find the absolute path
absImageFilename, err := filepath.Abs(imageFilename)
if err == nil {
imageFilename = absImageFilename
}

// Check that the file exists
if _, err := os.Stat(imageFilename); os.IsNotExist(err) {
// File does not exist
fmt.Fprintf(os.Stderr, "File does not exist: %s\n", imageFilename)
os.Exit(1)
}

// Set the desktop wallpaper
if err := monitor.SetWallpaper(imageFilename); err != nil {
fmt.Fprintf(os.Stderr, "Could not set wallpaper: %s\n", err)
os.Exit(1)
}
}
Loading

0 comments on commit 3a37f23

Please sign in to comment.