internal/ui: use the cursor position to choose the initial monitor

Updates #1982
This commit is contained in:
Hajime Hoshi 2022-02-07 21:56:16 +09:00
parent 126dc81a96
commit cafb71719c
2 changed files with 55 additions and 28 deletions

View File

@ -169,21 +169,32 @@ func initialize() error {
glfw.WindowHint(glfw.Visible, glfw.False)
glfw.WindowHint(glfw.ClientAPI, glfw.NoAPI)
// Create a window to set the initial monitor.
// TODO: Instead of a dummy window, get a mouse cursor position and get a monitor from it (#1982).
w, err := glfw.CreateWindow(16, 16, "", nil, nil)
if err != nil {
return err
var m *glfw.Monitor
if runtime.GOOS == "darwin" {
m = initialMonitorByOS()
if m == nil {
m = glfw.GetPrimaryMonitor()
}
} else {
// Create a window to set the initial monitor.
// TODO: Instead of a dummy window, get a mouse cursor position and get a monitor from it (#1982).
w, err := glfw.CreateWindow(16, 16, "", nil, nil)
if err != nil {
return err
}
if w == nil {
// This can happen on Windows Remote Desktop (#903).
panic("ui: glfw.CreateWindow must not return nil")
}
defer w.Destroy()
initializeWindowAfterCreation(w)
theUI.waitForFramebufferSizeCallback(w, nil)
m = initialMonitorByOS()
if m == nil {
m = currentMonitorImpl(w)
}
}
if w == nil {
// This can happen on Windows Remote Desktop (#903).
panic("ui: glfw.CreateWindow must not return nil")
}
defer w.Destroy()
initializeWindowAfterCreation(w)
theUI.waitForFramebufferSizeCallback(w, nil)
m := initialMonitor(w)
theUI.initMonitor = m
// GetVideoMode must be called from the main thread, then call this here and record
// initFullscreen{Width,Height}InDIP.
@ -914,8 +925,10 @@ func (u *UserInterface) init() error {
// Set the window size and the window position in this order on Linux or other UNIX using X (#1118),
// but this should be inverted on Windows. This is very tricky, but there is no obvious way to solve
// this. This doesn't matter on macOS.
// TODO: Set the position first even on X. setWindowSizeInDIP uses the monitor of the window, and
// if the window position is not reliable, the device scale factor is also not reliable (#1118, #1982).
wx, wy := u.getInitWindowPositionInDIP()
if runtime.GOOS == "windows" {
if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
u.setWindowPositionInDIP(wx, wy, u.initMonitor)
setSize()
} else {
@ -1345,18 +1358,6 @@ func (u *UserInterface) updateVsync() {
Graphics().SetVsyncEnabled(u.fpsMode == FPSModeVsyncOn)
}
// initialMonitor returns the initial monitor to show the window.
//
// The given window is just a hint and might not be used to determine the initial monitor.
//
// initialMonitor must be called on the main thread.
func initialMonitor(window *glfw.Window) *glfw.Monitor {
if m := initialMonitorByOS(); m != nil {
return m
}
return currentMonitorImpl(window)
}
// currentMonitor returns the current active monitor.
//
// currentMonitor must be called on the main thread.

View File

@ -120,6 +120,12 @@ package ui
// }
// [cursor push];
// }
//
// static void currentMouseLocation(int* x, int* y) {
// NSPoint location = [NSEvent mouseLocation];
// *x = (int)(location.x);
// *y = (int)(location.y);
// }
import "C"
import (
@ -153,12 +159,32 @@ func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) {
}
func initialMonitorByOS() *glfw.Monitor {
var cx, cy C.int
C.currentMouseLocation(&cx, &cy)
x, y := int(cx), int(cy)
// Flip Y.
for _, m := range ensureMonitors() {
if m.x == 0 && m.y == 0 {
y = -y
y += m.vm.Height
break
}
}
// Find the monitor including the cursor.
for _, m := range ensureMonitors() {
w, h := m.vm.Width, m.vm.Height
if x >= m.x && x < m.x+w && y >= m.y && y < m.y+h {
return m.m
}
}
return nil
}
func currentMonitorByOS(w *glfw.Window) *glfw.Monitor {
x := C.int(0)
y := C.int(0)
var x, y C.int
// Note: [NSApp mainWindow] is nil when it doesn't have its border. Use w here.
win := w.GetCocoaWindow()
C.currentMonitorPos(C.uintptr_t(win), &x, &y)