diff --git a/image.go b/image.go index 9f76338..51d6ae7 100644 --- a/image.go +++ b/image.go @@ -3,8 +3,6 @@ package main import ( "image" "os" - "syscall" - "unsafe" ) const defaultRatio float64 = 7.0 / 3.0 // The terminal's default cursor width/height ratio @@ -20,22 +18,6 @@ func load(filename string) (image.Image, error) { return img, err } -// canvasSize returns the terminal columns, rows, and cursor aspect ratio -func canvasSize() (int, int, float64) { - var size [4]uint16 - if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(os.Stdout.Fd()), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&size)), 0, 0, 0); err != 0 { - panic(err) - } - rows, cols, width, height := size[0], size[1], size[2], size[3] - - var whratio = defaultRatio - if width > 0 && height > 0 { - whratio = float64(height/rows) / float64(width/cols) - } - - return int(cols), int(rows), whratio -} - // scales calculates the image scale to fit within the terminal width/height func scale(imgW, imgH, termW, termH int, whratio float64) float64 { hr := float64(imgH) / (float64(termH) * whratio) diff --git a/size_unix.go b/size_unix.go new file mode 100644 index 0000000..a5a8a3e --- /dev/null +++ b/size_unix.go @@ -0,0 +1,36 @@ +// Builds for these work but not all the resultant binaries have been tested. +// +build darwin dragonfly freebsd linux netbsd openbsd + +// Note that as of at least termbox-go@v1.1.1 the following GOOS +// do not build (for termbox): +// aix +// illumos +// plan9 +// solaris +// For other reasons, pxl doesn't appear to build on GOOS: +// android +// ios + +package main + +import ( + "os" + "syscall" + "unsafe" +) + +// canvasSize returns the terminal columns, rows, and cursor aspect ratio +func canvasSize() (int, int, float64) { + var size [4]uint16 + if _, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(os.Stdout.Fd()), uintptr(syscall.TIOCGWINSZ), uintptr(unsafe.Pointer(&size)), 0, 0, 0); err != 0 { + panic(err) + } + rows, cols, width, height := size[0], size[1], size[2], size[3] + + var whratio = defaultRatio + if width > 0 && height > 0 { + whratio = float64(height/rows) / float64(width/cols) + } + + return int(cols), int(rows), whratio +} diff --git a/size_windows.go b/size_windows.go new file mode 100644 index 0000000..2827283 --- /dev/null +++ b/size_windows.go @@ -0,0 +1,79 @@ +package main + +import ( + "sync" + "syscall" + "unsafe" + + "github.com/nsf/termbox-go" +) + +// canvasSize returns the terminal columns, rows, and cursor aspect ratio +func canvasSize() (int, int, float64) { + cols, rows := termbox.Size() + var whratio = defaultRatio + if width, height, err := primarySize(); err == nil && width > 0 && height > 0 { + whratio = float64(height/rows) / float64(width/cols) + } + return cols, rows, whratio +} + +// Extracted (and trimmed down) from +// https://gist.github.com/dchapes/b90e4e0bde7d2672647b0d479ed42dbe +// (That's also why there are several functions and a bit more +// boiler plate that required for this one user32.dll call). + +const spiGetWorkArea = 0x0030 + +var winapi struct { + once sync.Once + systemParametersInfo uintptr + err error +} + +func loadWinAPI() { + winapi.once.Do(func() { + libuser32, err := syscall.LoadLibrary("user32.dll") + if err != nil { + winapi.err = err + return + } + winapi.systemParametersInfo, winapi.err = syscall.GetProcAddress(libuser32, "SystemParametersInfoW") + }) +} + +func systemParametersInfo(uiAction, uiParam uint32, pvParam unsafe.Pointer, fWinIni uint32) error { + loadWinAPI() + if winapi.err != nil { + return winapi.err + } + + r1, _, err := syscall.Syscall6(winapi.systemParametersInfo, 4, + uintptr(uiAction), uintptr(uiParam), + uintptr(pvParam), uintptr(fWinIni), 0, 0) + if r1 == 0 { + return err + } + return nil +} + +// primarySize returns the size of the primary display monitor. +func primarySize() (width, height int, err error) { + var rect struct { + left uint32 + top uint32 + right uint32 + bottom uint32 + // extra size as a safety margin + _ uint32 + _ uint32 + _ uint32 + _ uint32 + } + err = systemParametersInfo(spiGetWorkArea, 0, unsafe.Pointer(&rect.left), 0) + if err != nil { + return 0, 0, err + } + return int(rect.right) - int(rect.left), + int(rect.bottom) - int(rect.top), nil +}