Added monitor cache and scale cache (#731)

This commit is contained in:
Ben Echols 2018-11-07 04:54:37 -07:00 committed by Hajime Hoshi
parent b396b4f88a
commit 5e70fce639
3 changed files with 91 additions and 27 deletions

View File

@ -19,11 +19,14 @@
package devicescale
import (
"math"
"os"
"os/exec"
"regexp"
"strconv"
"strings"
"sync/atomic"
"time"
)
type desktop int
@ -37,6 +40,29 @@ const (
desktopXfce
)
var (
cachedScale uint64 // use atomic to read/write as multiple goroutines touch it.
cacheUpdateWait = time.Millisecond * 100
)
func init() {
go scaleUpdater()
}
func impl(x, y int) float64 {
return math.Float64frombits(atomic.LoadUint64(&cachedScale))
}
// run as goroutine. Will keep the desktop scale up to date.
// This can be removed once the scale change event is implemented in GLFW 3.3
func scaleUpdater() {
for {
s := getscale(0, 0)
atomic.StoreUint64(&cachedScale, math.Float64bits(s))
time.Sleep(cacheUpdateWait)
}
}
func currentDesktop() desktop {
tokens := strings.Split(os.Getenv("XDG_CURRENT_DESKTOP"), ":")
switch tokens[len(tokens)-1] {
@ -95,30 +121,24 @@ func cinnamonScale() float64 {
return float64(s)
}
func impl(x, y int) float64 {
// TODO: Can Linux has different scales for multiple monitors?
func getscale(x, y int) float64 {
s := -1.0
switch currentDesktop() {
case desktopGnome:
s := gnomeScale()
if s <= 0 {
return 1
}
return s
// TODO: Support wayland and per-monitor scaling https://wiki.gnome.org/HowDoI/HiDpi
s = gnomeScale()
case desktopCinnamon:
s := cinnamonScale()
if s <= 0 {
return 1
}
return s
s = cinnamonScale()
case desktopUnity:
// TODO: Implement
return 1
// TODO: Implement, supports per-monitor scaling
case desktopKDE:
// TODO: Implement
return 1
// TODO: Implement, appears to support per-monitor scaling
case desktopXfce:
// TODO: Implement
return 1
}
return 1
if s <= 0 {
s = 1
}
return s
}

View File

@ -76,6 +76,10 @@ func init() {
if err := initialize(); err != nil {
panic(err)
}
glfw.SetMonitorCallback(func(monitor *glfw.Monitor, event glfw.MonitorEvent) {
cacheMonitors()
})
cacheMonitors()
}
func initialize() error {
@ -117,6 +121,44 @@ func initialize() error {
return nil
}
type cachedMonitor struct {
m *glfw.Monitor
vm *glfw.VidMode
// Pos of monitor in virtual coords
x int
y int
}
// monitors is the monitor list cache for desktop glfw compile targets.
// populated by 'cacheMonitors' which is called on init and every
// monitor config change event.
var monitors []*cachedMonitor
func cacheMonitors() {
monitors = make([]*cachedMonitor, 0, 3)
ms := glfw.GetMonitors()
for _, m := range ms {
x, y := m.GetPos()
monitors = append(monitors, &cachedMonitor{
m: m,
vm: m.GetVideoMode(),
x: x,
y: y,
})
}
}
// getCachedMonitor returns a monitor for the given window x/y
// returns false if monitor is not found.
func getCachedMonitor(wx, wy int) (*cachedMonitor, bool) {
for _, m := range monitors {
if m.x <= wx && wx < m.x+m.vm.Width && m.y <= wy && wy < m.y+m.vm.Height {
return m, true
}
}
return nil, false
}
func Loop(ch <-chan error) error {
currentUI.setRunning(true)
if err := mainthread.Loop(ch); err != nil {
@ -552,6 +594,10 @@ func (u *userInterface) getScale() float64 {
// actualScreenScale must be called from the main thread.
func (u *userInterface) actualScreenScale() float64 {
// Avoid calling monitor.GetPos if we have the monitor position cached already.
if cm, ok := getCachedMonitor(u.window.GetPos()); ok {
return u.getScale() * devicescale.GetAt(cm.x, cm.y)
}
return u.getScale() * devicescale.GetAt(u.currentMonitor().GetPos())
}

View File

@ -26,7 +26,11 @@ import (
func glfwScale() float64 {
// This function must be called on the main thread.
return devicescale.GetAt(currentUI.currentMonitor().GetPos())
cm, ok := getCachedMonitor(currentUI.window.GetPos())
if !ok {
return devicescale.GetAt(currentUI.currentMonitor().GetPos())
}
return devicescale.GetAt(cm.x, cm.y)
}
func adjustWindowPosition(x, y int) (int, int) {
@ -35,14 +39,8 @@ func adjustWindowPosition(x, y int) (int, int) {
func (u *userInterface) currentMonitorImpl() *glfw.Monitor {
// TODO: Return more appropriate display.
w := u.window
wx, wy := w.GetPos()
for _, m := range glfw.GetMonitors() {
mx, my := m.GetPos()
v := m.GetVideoMode()
if mx <= wx && wx < mx+v.Width && my <= wy && wy < my+v.Height {
return m
}
if cm, ok := getCachedMonitor(u.window.GetPos()); ok {
return cm.m
}
return glfw.GetPrimaryMonitor()
}