ui_windows.go (5755B)
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 "runtime" 20 "unsafe" 21 22 "golang.org/x/sys/windows" 23 24 "github.com/hajimehoshi/ebiten/v2/internal/driver" 25 "github.com/hajimehoshi/ebiten/v2/internal/glfw" 26 ) 27 28 const ( 29 smCyCaption = 4 30 monitorDefaultToNearest = 2 31 ) 32 33 type rect struct { 34 left int32 35 top int32 36 right int32 37 bottom int32 38 } 39 40 type monitorInfo struct { 41 cbSize uint32 42 rcMonitor rect 43 rcWork rect 44 dwFlags uint32 45 } 46 47 var ( 48 // user32 is defined at hideconsole_windows.go 49 procGetSystemMetrics = user32.NewProc("GetSystemMetrics") 50 procGetActiveWindow = user32.NewProc("GetActiveWindow") 51 procGetForegroundWindow = user32.NewProc("GetForegroundWindow") 52 procMonitorFromWindow = user32.NewProc("MonitorFromWindow") 53 procGetMonitorInfoW = user32.NewProc("GetMonitorInfoW") 54 ) 55 56 func getSystemMetrics(nIndex int) (int, error) { 57 r, _, e := procGetSystemMetrics.Call(uintptr(nIndex)) 58 if e != nil && e.(windows.Errno) != 0 { 59 return 0, fmt.Errorf("ui: GetSystemMetrics failed: error code: %d", e) 60 } 61 return int(r), nil 62 } 63 64 func getActiveWindow() (uintptr, error) { 65 r, _, e := procGetActiveWindow.Call() 66 if e != nil && e.(windows.Errno) != 0 { 67 return 0, fmt.Errorf("ui: GetActiveWindow failed: error code: %d", e) 68 } 69 return r, nil 70 } 71 72 func getForegroundWindow() (uintptr, error) { 73 r, _, e := procGetForegroundWindow.Call() 74 if e != nil && e.(windows.Errno) != 0 { 75 return 0, fmt.Errorf("ui: GetForegroundWindow failed: error code: %d", e) 76 } 77 return r, nil 78 } 79 80 func monitorFromWindow(hwnd uintptr, dwFlags uint32) (uintptr, error) { 81 r, _, e := procMonitorFromWindow.Call(hwnd, uintptr(dwFlags)) 82 if e != nil && e.(windows.Errno) != 0 { 83 return 0, fmt.Errorf("ui: MonitorFromWindow failed: error code: %d", e) 84 } 85 if r == 0 { 86 return 0, fmt.Errorf("ui: MonitorFromWindow failed: returned value: %d", r) 87 } 88 return r, nil 89 } 90 91 func getMonitorInfoW(hMonitor uintptr, lpmi *monitorInfo) error { 92 r, _, e := procGetMonitorInfoW.Call(hMonitor, uintptr(unsafe.Pointer(lpmi))) 93 if e != nil && e.(windows.Errno) != 0 { 94 return fmt.Errorf("ui: GetMonitorInfoW failed: error code: %d", e) 95 } 96 if r == 0 { 97 return fmt.Errorf("ui: GetMonitorInfoW failed: returned value: %d", r) 98 } 99 return nil 100 } 101 102 // clearVideoModeScaleCache must be called from the main thread. 103 func clearVideoModeScaleCache() {} 104 105 // videoModeScale must be called from the main thread. 106 func videoModeScale(m *glfw.Monitor) float64 { 107 return 1 108 } 109 110 // fromGLFWMonitorPixel must be called from the main thread. 111 func (u *UserInterface) fromGLFWMonitorPixel(x float64, videoModeScale float64) float64 { 112 return x / (videoModeScale * u.deviceScaleFactor()) 113 } 114 115 // fromGLFWPixel must be called from the main thread. 116 func (u *UserInterface) fromGLFWPixel(x float64) float64 { 117 return x / u.deviceScaleFactor() 118 } 119 120 // toGLFWPixel must be called from the main thread. 121 func (u *UserInterface) toGLFWPixel(x float64) float64 { 122 return x * u.deviceScaleFactor() 123 } 124 125 func (u *UserInterface) adjustWindowPosition(x, y int) (int, int) { 126 mx, my := currentMonitor(u.window).GetPos() 127 // As the video width/height might be wrong, 128 // adjust x/y at least to enable to handle the window (#328) 129 if x < mx { 130 x = mx 131 } 132 t, err := getSystemMetrics(smCyCaption) 133 if err != nil { 134 panic(err) 135 } 136 if y < my+t { 137 y = my + t 138 } 139 return x, y 140 } 141 142 func currentMonitorByOS(_ *glfw.Window) *glfw.Monitor { 143 // TODO: Why not using the given window? 144 145 // TODO: Should we return nil here? 146 w, err := getActiveWindow() 147 if err != nil { 148 panic(err) 149 } 150 151 if w == 0 { 152 // The active window doesn't exist when launching, or the application is runnable on unfocused. 153 // Get the foreground window, that is common among multiple processes. 154 w, err = getForegroundWindow() 155 if err != nil { 156 panic(err) 157 } 158 if w == 0 { 159 // GetForegroundWindow can return null according to the document. 160 return nil 161 } 162 } 163 164 // Get the current monitor by the window handle instead of the window position. It is because the window 165 // position is not relaiable in some cases e.g. when the window is put across multiple monitors. 166 167 m, err := monitorFromWindow(w, monitorDefaultToNearest) 168 if err != nil { 169 // monitorFromWindow can return error on Wine. Ignore this. 170 return nil 171 } 172 173 mi := monitorInfo{} 174 mi.cbSize = uint32(unsafe.Sizeof(mi)) 175 if err := getMonitorInfoW(m, &mi); err != nil { 176 panic(err) 177 } 178 179 x, y := int(mi.rcMonitor.left), int(mi.rcMonitor.top) 180 for _, m := range ensureMonitors() { 181 if m.x == x && m.y == y { 182 return m.m 183 } 184 } 185 return nil 186 } 187 188 func (u *UserInterface) nativeWindow() uintptr { 189 return u.window.GetWin32Window() 190 } 191 192 func (u *UserInterface) isNativeFullscreen() bool { 193 return false 194 } 195 196 func (u *UserInterface) setNativeCursor(shape driver.CursorShape) { 197 // TODO: Use native API in the future (#1571) 198 u.window.SetCursor(glfwSystemCursors[shape]) 199 } 200 201 func (u *UserInterface) isNativeFullscreenAvailable() bool { 202 return false 203 } 204 205 func (u *UserInterface) setNativeFullscreen(fullscreen bool) { 206 panic(fmt.Sprintf("glfw: setNativeFullscreen is not implemented in this environment: %s", runtime.GOOS)) 207 } 208 209 func (u *UserInterface) adjustViewSize() { 210 } 211 212 func initializeWindowAfterCreation(w *glfw.Window) { 213 }