ui_windows.go (4962B)
1 // Copyright 2016 Hajime Hoshi 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package glfw 16 17 import ( 18 "fmt" 19 "unsafe" 20 21 "golang.org/x/sys/windows" 22 23 "github.com/hajimehoshi/ebiten/v2/internal/glfw" 24 ) 25 26 const ( 27 smCyCaption = 4 28 monitorDefaultToNearest = 2 29 ) 30 31 type rect struct { 32 left int32 33 top int32 34 right int32 35 bottom int32 36 } 37 38 type monitorInfo struct { 39 cbSize uint32 40 rcMonitor rect 41 rcWork rect 42 dwFlags uint32 43 } 44 45 var ( 46 // user32 is defined at hideconsole_windows.go 47 procGetSystemMetrics = user32.NewProc("GetSystemMetrics") 48 procGetActiveWindow = user32.NewProc("GetActiveWindow") 49 procGetForegroundWindow = user32.NewProc("GetForegroundWindow") 50 procMonitorFromWindow = user32.NewProc("MonitorFromWindow") 51 procGetMonitorInfoW = user32.NewProc("GetMonitorInfoW") 52 ) 53 54 func getSystemMetrics(nIndex int) (int, error) { 55 r, _, e := procGetSystemMetrics.Call(uintptr(nIndex)) 56 if e != nil && e.(windows.Errno) != 0 { 57 return 0, fmt.Errorf("ui: GetSystemMetrics failed: error code: %d", e) 58 } 59 return int(r), nil 60 } 61 62 func getActiveWindow() (uintptr, error) { 63 r, _, e := procGetActiveWindow.Call() 64 if e != nil && e.(windows.Errno) != 0 { 65 return 0, fmt.Errorf("ui: GetActiveWindow failed: error code: %d", e) 66 } 67 return r, nil 68 } 69 70 func getForegroundWindow() (uintptr, error) { 71 r, _, e := procGetForegroundWindow.Call() 72 if e != nil && e.(windows.Errno) != 0 { 73 return 0, fmt.Errorf("ui: GetForegroundWindow failed: error code: %d", e) 74 } 75 return r, nil 76 } 77 78 func monitorFromWindow(hwnd uintptr, dwFlags uint32) (uintptr, error) { 79 r, _, e := procMonitorFromWindow.Call(hwnd, uintptr(dwFlags)) 80 if e != nil && e.(windows.Errno) != 0 { 81 return 0, fmt.Errorf("ui: MonitorFromWindow failed: error code: %d", e) 82 } 83 if r == 0 { 84 return 0, fmt.Errorf("ui: MonitorFromWindow failed: returned value: %d", r) 85 } 86 return r, nil 87 } 88 89 func getMonitorInfoW(hMonitor uintptr, lpmi *monitorInfo) error { 90 r, _, e := procGetMonitorInfoW.Call(hMonitor, uintptr(unsafe.Pointer(lpmi))) 91 if e != nil && e.(windows.Errno) != 0 { 92 return fmt.Errorf("ui: GetMonitorInfoW failed: error code: %d", e) 93 } 94 if r == 0 { 95 return fmt.Errorf("ui: GetMonitorInfoW failed: returned value: %d", r) 96 } 97 return nil 98 } 99 100 // fromGLFWMonitorPixel must be called from the main thread. 101 func (u *UserInterface) fromGLFWMonitorPixel(x float64) float64 { 102 return x / u.deviceScaleFactor() 103 } 104 105 // fromGLFWPixel must be called from the main thread. 106 func (u *UserInterface) fromGLFWPixel(x float64) float64 { 107 return x / u.deviceScaleFactor() 108 } 109 110 // toGLFWPixel must be called from the main thread. 111 func (u *UserInterface) toGLFWPixel(x float64) float64 { 112 return x * u.deviceScaleFactor() 113 } 114 115 // toFramebufferPixel must be called from the main thread. 116 func (u *UserInterface) toFramebufferPixel(x float64) float64 { 117 return x 118 } 119 120 func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) { 121 mx, my := currentMonitor(u.window).GetPos() 122 // As the video width/height might be wrong, 123 // adjust x/y at least to enable to handle the window (#328) 124 if x < mx { 125 x = mx 126 } 127 t, err := getSystemMetrics(smCyCaption) 128 if err != nil { 129 panic(err) 130 } 131 if y < my+t { 132 y = my + t 133 } 134 return x, y 135 } 136 137 func currentMonitorByOS(_ *glfw.Window) *glfw.Monitor { 138 // TODO: Should we return nil here? 139 w, err := getActiveWindow() 140 if err != nil { 141 panic(err) 142 } 143 144 if w == 0 { 145 // The active window doesn't exist when launching, or the application is runnable on unfocused. 146 // Get the foreground window, that is common among multiple processes. 147 w, err = getForegroundWindow() 148 if err != nil { 149 panic(err) 150 } 151 if w == 0 { 152 // GetForegroundWindow can return null according to the document. 153 return nil 154 } 155 } 156 157 // Get the current monitor by the window handle instead of the window position. It is because the window 158 // position is not relaiable in some cases e.g. when the window is put across multiple monitors. 159 160 m, err := monitorFromWindow(w, monitorDefaultToNearest) 161 if err != nil { 162 // monitorFromWindow can return error on Wine. Ignore this. 163 return nil 164 } 165 166 mi := monitorInfo{} 167 mi.cbSize = uint32(unsafe.Sizeof(mi)) 168 if err := getMonitorInfoW(m, &mi); err != nil { 169 panic(err) 170 } 171 172 x, y := int(mi.rcMonitor.left), int(mi.rcMonitor.top) 173 for _, m := range glfw.GetMonitors() { 174 mx, my := m.GetPos() 175 if mx == x && my == y { 176 return m 177 } 178 } 179 return nil 180 } 181 182 func (u *UserInterface) nativeWindow() uintptr { 183 return u.window.GetWin32Window() 184 }