devicescale: Specify the monitor to get the scale

Fixes #695
This commit is contained in:
Hajime Hoshi 2018-10-06 17:29:40 +09:00
parent b99cc6ca8e
commit 55a397bd65
10 changed files with 56 additions and 43 deletions

View File

@ -23,7 +23,11 @@ var (
)
func Get() float64 {
return GetAt(0, 0)
}
func GetAt(x, y int) float64 {
m.Lock()
defer m.Unlock()
return impl()
return impl(x, y)
}

View File

@ -63,7 +63,7 @@ import (
"golang.org/x/mobile/app"
)
func impl() float64 {
func impl(x, y int) float64 {
s := 0.0
if err := app.RunOnJVM(func(vm, env, ctx uintptr) error {
// TODO: This might be crash when this is called from init(). How can we detect this?

View File

@ -26,6 +26,6 @@ package devicescale
// }
import "C"
func impl() float64 {
func impl(x, y int) float64 {
return float64(C.devicePixelRatio())
}

View File

@ -20,7 +20,7 @@ import (
"github.com/gopherjs/gopherwasm/js"
)
func impl() float64 {
func impl(x, y int) float64 {
ratio := js.Global().Get("window").Get("devicePixelRatio").Float()
if ratio == 0 {
ratio = 1

View File

@ -23,12 +23,17 @@ package devicescale
//
// #import <AppKit/AppKit.h>
//
// static float scale() {
// NSScreen* current = [NSScreen mainScreen];
// return [current backingScaleFactor];
// static float scaleAt(int x, int y) {
// NSArray<NSScreen*>* screens = [NSScreen screens];
// for (NSScreen* screen in screens) {
// if (NSPointInRect(NSMakePoint(x, y), [screen frame])) {
// return [screen backingScaleFactor];
// }
// }
// return 0;
// }
import "C"
func impl() float64 {
return float64(C.scale())
func impl(x, y int) float64 {
return float64(C.scaleAt(C.int(x), C.int(y)))
}

View File

@ -95,7 +95,8 @@ func cinnamonScale() float64 {
return float64(s)
}
func impl() float64 {
func impl(x, y int) float64 {
// TODO: Can Linux has different scales for multiple monitors?
switch currentDesktop() {
case desktopGnome:
s := gnomeScale()

View File

@ -24,10 +24,18 @@ import (
const (
logPixelsX = 88
monitorDefaultToNull = 0
monitorDefaultToNearest = 2
mdtEffectiveDpi = 0
)
type rect struct {
left int32
top int32
right int32
bottom int32
}
var (
user32 = syscall.NewLazyDLL("user32")
gdi32 = syscall.NewLazyDLL("gdi32")
@ -36,10 +44,9 @@ var (
var (
procSetProcessDPIAware = user32.NewProc("SetProcessDPIAware")
procGetActiveWindow = user32.NewProc("GetActiveWindow")
procGetWindowDC = user32.NewProc("GetWindowDC")
procReleaseDC = user32.NewProc("ReleaseDC")
procMonitorFromWindow = user32.NewProc("MonitorFromWindow")
procMonitorFromRect = user32.NewProc("MonitorFromRect")
procGetMonitorInfo = user32.NewProc("GetMonitorInfoW")
procGetDeviceCaps = gdi32.NewProc("GetDeviceCaps")
@ -68,14 +75,6 @@ func setProcessDPIAware() error {
return nil
}
func getActiveWindow() (uintptr, error) {
r, _, e := syscall.Syscall(procGetActiveWindow.Addr(), 0, 0, 0, 0)
if e != 0 {
return 0, fmt.Errorf("devicescale: GetActiveWindow failed: error code: %d", e)
}
return r, nil
}
func getWindowDC(hwnd uintptr) (uintptr, error) {
r, _, e := syscall.Syscall(procGetWindowDC.Addr(), 1, hwnd, 0, 0)
if e != 0 {
@ -106,13 +105,13 @@ func getDeviceCaps(hdc uintptr, nindex int) (int, error) {
return int(r), nil
}
func monitorFromWindow(hwnd uintptr, dwFlags int) (uintptr, error) {
r, _, e := syscall.Syscall(procMonitorFromWindow.Addr(), 2, hwnd, uintptr(dwFlags), 0)
func monitorFromRect(lprc uintptr, dwFlags int) (uintptr, error) {
r, _, e := syscall.Syscall(procMonitorFromRect.Addr(), 2, lprc, uintptr(dwFlags), 0)
if e != 0 {
return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: error code: %d", e)
return 0, fmt.Errorf("devicescale: MonitorFromRect failed: error code: %d", e)
}
if r == 0 {
return 0, fmt.Errorf("devicescale: MonitorFromWindow failed: returned value: %d", r)
return 0, fmt.Errorf("devicescale: MonitorFromRect failed: returned value: %d", r)
}
return r, nil
}
@ -160,7 +159,7 @@ func getFromLogPixelSx() float64 {
return float64(dpi) / 96
}
func impl() float64 {
func impl(x, y int) float64 {
if err := setProcessDPIAware(); err != nil {
panic(err)
}
@ -170,17 +169,16 @@ func impl() float64 {
return getFromLogPixelSx()
}
w, err := getActiveWindow()
if err != nil {
panic(err)
}
// The window is not initialized yet when w == 0.
if w == 0 {
// TODO: Use the primary monitor instead.
return getFromLogPixelSx()
lprc := rect{
left: int32(x),
right: int32(x + 1),
top: int32(y),
bottom: int32(y + 1),
}
m, err := monitorFromWindow(w, monitorDefaultToNearest)
// MonitorFromPoint requires to pass a POINT value, and there seems no portable way to
// do this with Cgo. Use MonitorFromRect instead.
m, err := monitorFromRect(uintptr(unsafe.Pointer(&lprc)), monitorDefaultToNull)
if err != nil {
panic(err)
}

View File

@ -28,6 +28,7 @@ import (
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/hajimehoshi/ebiten/internal/devicescale"
"github.com/hajimehoshi/ebiten/internal/hooks"
"github.com/hajimehoshi/ebiten/internal/input"
"github.com/hajimehoshi/ebiten/internal/opengl"
@ -390,8 +391,9 @@ func ScreenPadding() (x0, y0, x1, y1 float64) {
return ox, 0, ox, 0
}
v := u.window.GetMonitor().GetVideoMode()
d := u.deviceScale.Get()
m := u.window.GetMonitor()
d := devicescale.GetAt(m.GetPos())
v := m.GetVideoMode()
mx := float64(v.Width) * d / glfwScale()
my := float64(v.Height) * d / glfwScale()
@ -500,8 +502,6 @@ func Run(width, height int, scale float64, title string, g GraphicsContext, main
// swapping buffers.
opengl.Init(currentUI.runOnMainThread)
_ = u.runOnMainThread(func() error {
v := u.currentMonitor().GetVideoMode()
// The game is in window mode (not fullscreen mode) at the first state.
// Don't refer u.initFullscreen here to avoid some GLFW problems.
u.setScreenSize(width, height, scale, false, u.vsync)
@ -509,6 +509,7 @@ func Run(width, height int, scale float64, title string, g GraphicsContext, main
u.window.SetTitle(title)
u.window.Show()
v := u.currentMonitor().GetVideoMode()
w, h := u.glfwSize()
x := (v.Width - w) / 2
y := (v.Height - h) / 3
@ -546,7 +547,7 @@ func (u *userInterface) getScale() float64 {
// actualScreenScale must be called from the main thread.
func (u *userInterface) actualScreenScale() float64 {
return u.getScale() * u.deviceScale.Get()
return u.getScale() * devicescale.GetAt(u.currentMonitor().GetPos())
}
// pollEvents must be called from the main thread.
@ -638,7 +639,6 @@ func (u *userInterface) loop(g GraphicsContext) error {
return err
}
u.deviceScale.Update()
u.m.Lock()
vsync := u.vsync
u.m.Unlock()
@ -692,7 +692,7 @@ func (u *userInterface) forceSetScreenSize(width, height int, scale float64, ful
u.width = width
u.windowWidth = width
s := scale * u.deviceScale.Get()
s := scale * devicescale.GetAt(u.currentMonitor().GetPos())
if int(float64(width)*s) < minWindowWidth {
u.windowWidth = int(math.Ceil(minWindowWidth / s))
}

View File

@ -23,7 +23,8 @@ import (
)
func glfwScale() float64 {
return devicescale.Get()
// This function must be called on the main thread.
return devicescale.GetAt(currentUI.currentMonitor().GetPos())
}
func adjustWindowPosition(x, y int) (int, int) {

View File

@ -27,9 +27,13 @@ package ui
// }
import "C"
import (
"github.com/hajimehoshi/ebiten/internal/devicescale"
)
func glfwScale() float64 {
// This function must be called on the main thread.
return currentUI.deviceScale.Get()
return devicescale.GetAt(currentUI.currentMonitor().GetPos())
}
func adjustWindowPosition(x, y int) (int, int) {