internal/goglfw: separate the Windows version detection to a new package winver

This commit is contained in:
Hajime Hoshi 2023-03-31 02:07:35 +09:00
parent c0adcee12c
commit 182ac21866
10 changed files with 221 additions and 228 deletions

View File

@ -164,11 +164,6 @@ const (
_TME_LEAVE = 0x00000002 _TME_LEAVE = 0x00000002
_UNICODE_NOCHAR = 0xffff _UNICODE_NOCHAR = 0xffff
_USER_DEFAULT_SCREEN_DPI = 96 _USER_DEFAULT_SCREEN_DPI = 96
_VER_BUILDNUMBER = 0x00000004
_VER_GREATER_EQUAL = 3
_VER_MAJORVERSION = 0x00000002
_VER_MINORVERSION = 0x00000001
_VER_SERVICEPACKMAJOR = 0x00000020
_VERTSIZE = 6 _VERTSIZE = 6
_VK_ADD = 0x6B _VK_ADD = 0x6B
_VK_CAPITAL = 0x14 _VK_CAPITAL = 0x14
@ -262,11 +257,6 @@ const (
_WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B _WGL_TRANSPARENT_INDEX_VALUE_ARB = 0x203B
_WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037 _WGL_TRANSPARENT_RED_VALUE_ARB = 0x2037
_WGL_TYPE_RGBA_ARB = 0x202B _WGL_TYPE_RGBA_ARB = 0x202B
_WIN32_WINNT_VISTA = 0x0600
_WIN32_WINNT_WIN7 = 0x0601
_WIN32_WINNT_WIN8 = 0x0602
_WIN32_WINNT_WINBLUE = 0x0603
_WIN32_WINNT_WINXP = 0x0501
_WM_CAPTURECHANGED = 0x0215 _WM_CAPTURECHANGED = 0x0215
_WM_CHAR = 0x0102 _WM_CHAR = 0x0102
_WM_CLOSE = 0x0010 _WM_CLOSE = 0x0010
@ -387,18 +377,11 @@ func _GET_XBUTTON_WPARAM(wParam _WPARAM) uint16 {
func _GET_Y_LPARAM(lp _LPARAM) int { func _GET_Y_LPARAM(lp _LPARAM) int {
return int(_HIWORD(uint32(lp))) return int(_HIWORD(uint32(lp)))
} }
func _HIBYTE(wValue uint16) byte {
return byte(wValue >> 8)
}
func _HIWORD(dwValue uint32) uint16 { func _HIWORD(dwValue uint32) uint16 {
return uint16(dwValue >> 16) return uint16(dwValue >> 16)
} }
func _LOBYTE(wValue uint16) byte {
return byte(wValue)
}
func _LOWORD(dwValue uint32) uint16 { func _LOWORD(dwValue uint32) uint16 {
return uint16(dwValue) return uint16(dwValue)
} }
@ -590,20 +573,6 @@ type _MSG struct {
lPrivate uint32 lPrivate uint32
} }
type _OSVERSIONINFOEXW struct {
dwOSVersionInfoSize uint32
dwMajorVersion uint32
dwMinorVersion uint32
dwBuildNumber uint32
dwPlatformId uint32
szCSDVersion [128]uint16
wServicePackMajor uint16
wServicePackMinor uint16
wSuiteMask uint16
wProductType byte
wReserved byte
}
type _PIXELFORMATDESCRIPTOR struct { type _PIXELFORMATDESCRIPTOR struct {
nSize uint16 nSize uint16
nVersion uint16 nVersion uint16
@ -722,7 +691,6 @@ var (
dwmapi = windows.NewLazySystemDLL("dwmapi.dll") dwmapi = windows.NewLazySystemDLL("dwmapi.dll")
gdi32 = windows.NewLazySystemDLL("gdi32.dll") gdi32 = windows.NewLazySystemDLL("gdi32.dll")
kernel32 = windows.NewLazySystemDLL("kernel32.dll") kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
opengl32 = windows.NewLazySystemDLL("opengl32.dll") opengl32 = windows.NewLazySystemDLL("opengl32.dll")
shcore = windows.NewLazySystemDLL("shcore.dll") shcore = windows.NewLazySystemDLL("shcore.dll")
shell32 = windows.NewLazySystemDLL("shell32.dll") shell32 = windows.NewLazySystemDLL("shell32.dll")
@ -749,9 +717,6 @@ var (
procTlsFree = kernel32.NewProc("TlsFree") procTlsFree = kernel32.NewProc("TlsFree")
procTlsGetValue = kernel32.NewProc("TlsGetValue") procTlsGetValue = kernel32.NewProc("TlsGetValue")
procTlsSetValue = kernel32.NewProc("TlsSetValue") procTlsSetValue = kernel32.NewProc("TlsSetValue")
procVerSetConditionMask = kernel32.NewProc("VerSetConditionMask")
procRtlVerifyVersionInfo = ntdll.NewProc("RtlVerifyVersionInfo")
procWGLCreateContext = opengl32.NewProc("wglCreateContext") procWGLCreateContext = opengl32.NewProc("wglCreateContext")
procWGLDeleteContext = opengl32.NewProc("wglDeleteContext") procWGLDeleteContext = opengl32.NewProc("wglDeleteContext")
@ -1522,24 +1487,6 @@ func _ReleaseDC(hWnd windows.HWND, hDC _HDC) int32 {
return int32(r) return int32(r)
} }
func _RtlVerifyVersionInfo(versionInfo *_OSVERSIONINFOEXW, typeMask uint32, conditionMask uint64) int32 {
var r uintptr
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask))
} else {
switch runtime.GOARCH {
case "386":
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask), uintptr(conditionMask>>32))
case "arm":
// Adjust the alignment for ARM.
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), 0, uintptr(conditionMask), uintptr(conditionMask>>32))
default:
panic(fmt.Sprintf("goglfw: GOARCH=%s is not supported", runtime.GOARCH))
}
}
return int32(r)
}
func _ScreenToClient(hWnd windows.HWND, lpPoint *_POINT) error { func _ScreenToClient(hWnd windows.HWND, lpPoint *_POINT) error {
r, _, e := procScreenToClient.Call(uintptr(hWnd), uintptr(unsafe.Pointer(lpPoint))) r, _, e := procScreenToClient.Call(uintptr(hWnd), uintptr(unsafe.Pointer(lpPoint)))
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) { if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {
@ -1777,16 +1724,6 @@ func _UnregisterDeviceNotification(handle _HDEVNOTIFY) error {
return nil return nil
} }
func _VerSetConditionMask(conditionMask uint64, typeMask uint32, condition byte) uint64 {
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(typeMask), uintptr(condition))
return uint64(r)
} else {
r1, r2, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(conditionMask>>32), uintptr(typeMask), uintptr(condition))
return uint64(r1) | (uint64(r2) << 32)
}
}
func _WaitMessage() error { func _WaitMessage() error {
r, _, e := procWaitMessage.Call() r, _, e := procWaitMessage.Call()
if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) { if int32(r) == 0 && !errors.Is(e, windows.ERROR_SUCCESS) {

View File

@ -14,6 +14,7 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
) )
func findPixelFormatAttribValue(attribs []int32, values []int32, attrib int32) int32 { func findPixelFormatAttribValue(attribs []int32, values []int32, attrib int32) int32 {
@ -230,9 +231,9 @@ func makeContextCurrentWGL(window *Window) error {
} }
func swapBuffersWGL(window *Window) error { func swapBuffersWGL(window *Window) error {
if window.monitor == nil && _IsWindowsVistaOrGreater() { if window.monitor == nil && winver.IsWindowsVistaOrGreater() {
// DWM Composition is always enabled on Win8+ // DWM Composition is always enabled on Win8+
enabled := _IsWindows8OrGreater() enabled := winver.IsWindows8OrGreater()
if !enabled { if !enabled {
var err error var err error
@ -266,9 +267,9 @@ func swapIntervalWGL(interval int) error {
window.context.platform.interval = interval window.context.platform.interval = interval
if window.monitor == nil && _IsWindowsVistaOrGreater() { if window.monitor == nil && winver.IsWindowsVistaOrGreater() {
// DWM Composition is always enabled on Win8+ // DWM Composition is always enabled on Win8+
enabled := _IsWindows8OrGreater() enabled := winver.IsWindows8OrGreater()
if !enabled { if !enabled {
e, err := _DwmIsCompositionEnabled() e, err := _DwmIsCompositionEnabled()

View File

@ -12,6 +12,7 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
) )
func createKeyTables() { func createKeyTables() {
@ -238,41 +239,6 @@ func createHelperWindow() error {
return nil return nil
} }
func isWindowsVersionOrGreaterWin32(major, minor, sp uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: uint32(major),
dwMinorVersion: uint32(minor),
wServicePackMajor: sp,
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_SERVICEPACKMAJOR
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_SERVICEPACKMAJOR, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func isWindows10BuildOrGreaterWin32(build uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: uint32(build),
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_BUILDNUMBER
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_BUILDNUMBER, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func platformInit() error { func platformInit() error {
// Changing the foreground lock timeout was removed from the original code. // Changing the foreground lock timeout was removed from the original code.
// See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4 // See https://github.com/glfw/glfw/commit/58b48a3a00d9c2a5ca10cc23069a71d8773cc7a4
@ -286,17 +252,17 @@ func platformInit() error {
createKeyTables() createKeyTables()
updateKeyNamesWin32() updateKeyNamesWin32()
if isWindows10CreatorsUpdateOrGreaterWin32() { if winver.IsWindows10CreatorsUpdateOrGreater() {
if !microsoftgdk.IsXbox() { if !microsoftgdk.IsXbox() {
// Ignore the error as SetProcessDpiAwarenessContext returns an error on Steam Deck (#2113). // Ignore the error as SetProcessDpiAwarenessContext returns an error on Steam Deck (#2113).
// This seems an issue in Wine and/or Proton, but there is nothing we can do. // This seems an issue in Wine and/or Proton, but there is nothing we can do.
_ = _SetProcessDpiAwarenessContext(_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2) _ = _SetProcessDpiAwarenessContext(_DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2)
} }
} else if _IsWindows8Point1OrGreater() { } else if winver.IsWindows8Point1OrGreater() {
if err := _SetProcessDpiAwareness(_PROCESS_PER_MONITOR_DPI_AWARE); err != nil && !errors.Is(err, handleError(windows.E_ACCESSDENIED)) { if err := _SetProcessDpiAwareness(_PROCESS_PER_MONITOR_DPI_AWARE); err != nil && !errors.Is(err, handleError(windows.E_ACCESSDENIED)) {
return err return err
} }
} else if _IsWindowsVistaOrGreater() { } else if winver.IsWindowsVistaOrGreater() {
_SetProcessDPIAware() _SetProcessDPIAware()
} }

View File

@ -12,6 +12,7 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
) )
func monitorCallback(handle _HMONITOR, dc _HDC, rect *_RECT, monitor *Monitor /* _LPARAM */) uintptr /* _BOOL */ { func monitorCallback(handle _HMONITOR, dc _HDC, rect *_RECT, monitor *Monitor /* _LPARAM */) uintptr /* _BOOL */ {
@ -217,7 +218,7 @@ func (m *Monitor) restoreVideoModeWin32() {
func getMonitorContentScaleWin32(handle _HMONITOR) (xscale, yscale float32, err error) { func getMonitorContentScaleWin32(handle _HMONITOR) (xscale, yscale float32, err error) {
var xdpi, ydpi uint32 var xdpi, ydpi uint32
if _IsWindows8Point1OrGreater() { if winver.IsWindows8Point1OrGreater() {
var err error var err error
xdpi, ydpi, err = _GetDpiForMonitor(handle, _MDT_EFFECTIVE_DPI) xdpi, ydpi, err = _GetDpiForMonitor(handle, _MDT_EFFECTIVE_DPI)
if err != nil { if err != nil {

View File

@ -5,7 +5,9 @@
package goglfw package goglfw
import "golang.org/x/sys/windows" import (
"golang.org/x/sys/windows"
)
const ( const (
_GLFW_WNDCLASSNAME = "GLFW30" _GLFW_WNDCLASSNAME = "GLFW30"
@ -96,31 +98,3 @@ type platformLibraryContextState struct {
ARB_create_context_no_error bool ARB_create_context_no_error bool
ARB_context_flush_control bool ARB_context_flush_control bool
} }
func _IsWindowsXPOrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WINXP)), uint16(_LOBYTE(_WIN32_WINNT_WINXP)), 0)
}
func _IsWindowsVistaOrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_VISTA)), uint16(_LOBYTE(_WIN32_WINNT_VISTA)), 0)
}
func _IsWindows7OrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WIN7)), uint16(_LOBYTE(_WIN32_WINNT_WIN7)), 0)
}
func _IsWindows8OrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WIN8)), uint16(_LOBYTE(_WIN32_WINNT_WIN8)), 0)
}
func _IsWindows8Point1OrGreater() bool {
return isWindowsVersionOrGreaterWin32(uint16(_HIBYTE(_WIN32_WINNT_WINBLUE)), uint16(_LOBYTE(_WIN32_WINNT_WINBLUE)), 0)
}
func isWindows10AnniversaryUpdateOrGreaterWin32() bool {
return isWindows10BuildOrGreaterWin32(14393)
}
func isWindows10CreatorsUpdateOrGreaterWin32() bool {
return isWindows10BuildOrGreaterWin32(15063)
}

View File

@ -15,6 +15,7 @@ import (
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
) )
func (w *Window) getWindowStyle() uint32 { func (w *Window) getWindowStyle() uint32 {
@ -137,7 +138,7 @@ func getFullWindowSize(style uint32, exStyle uint32, contentWidth, contentHeight
right: int32(contentWidth), right: int32(contentWidth),
bottom: int32(contentHeight), bottom: int32(contentHeight),
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil { if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil {
return 0, 0, err return 0, 0, err
} }
@ -153,7 +154,7 @@ func (w *Window) applyAspectRatio(edge int, area *_RECT) error {
ratio := float32(w.numer) / float32(w.denom) ratio := float32(w.numer) / float32(w.denom)
var dpi uint32 = _USER_DEFAULT_SCREEN_DPI var dpi uint32 = _USER_DEFAULT_SCREEN_DPI
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
dpi = _GetDpiForWindow(w.platform.handle) dpi = _GetDpiForWindow(w.platform.handle)
} }
@ -343,7 +344,7 @@ func (w *Window) updateWindowStyles() error {
return err return err
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, style, false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil { if err := _AdjustWindowRectExForDpi(&rect, style, false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err return err
} }
@ -368,7 +369,7 @@ func (w *Window) updateWindowStyles() error {
} }
func (w *Window) updateFramebufferTransparency() error { func (w *Window) updateFramebufferTransparency() error {
if !_IsWindowsVistaOrGreater() { if !winver.IsWindowsVistaOrGreater() {
return nil return nil
} }
@ -382,7 +383,7 @@ func (w *Window) updateFramebufferTransparency() error {
} }
var opaque bool var opaque bool
if !_IsWindows8OrGreater() { if !winver.IsWindows8OrGreater() {
_, opaque, err = _DwmGetColorizationColor() _, opaque, err = _DwmGetColorizationColor()
if err != nil { if err != nil {
// Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113). // Ignore an error from DWM functions as they might not be implemented e.g. on Proton (#2113).
@ -390,7 +391,7 @@ func (w *Window) updateFramebufferTransparency() error {
} }
} }
if _IsWindows8OrGreater() || !opaque { if winver.IsWindows8OrGreater() || !opaque {
region, err := _CreateRectRgn(0, 0, -1, -1) region, err := _CreateRectRgn(0, 0, -1, -1)
if err != nil { if err != nil {
return err return err
@ -473,7 +474,7 @@ func (w *Window) acquireMonitor() error {
// HACK: When mouse trails are enabled the cursor becomes invisible when // HACK: When mouse trails are enabled the cursor becomes invisible when
// the OpenGL ICD switches to page flipping // the OpenGL ICD switches to page flipping
if _IsWindowsXPOrGreater() { if winver.IsWindowsXPOrGreater() {
if err := _SystemParametersInfoW(_SPI_GETMOUSETRAILS, 0, uintptr(unsafe.Pointer(&_glfw.platformWindow.mouseTrailSize)), 0); err != nil { if err := _SystemParametersInfoW(_SPI_GETMOUSETRAILS, 0, uintptr(unsafe.Pointer(&_glfw.platformWindow.mouseTrailSize)), 0); err != nil {
return err return err
} }
@ -504,7 +505,7 @@ func (w *Window) releaseMonitor() error {
_SetThreadExecutionState(_ES_CONTINUOUS) _SetThreadExecutionState(_ES_CONTINUOUS)
// HACK: Restore mouse trail length saved in acquireMonitor // HACK: Restore mouse trail length saved in acquireMonitor
if _IsWindowsXPOrGreater() { if winver.IsWindowsXPOrGreater() {
if err := _SystemParametersInfoW(_SPI_SETMOUSETRAILS, _glfw.platformWindow.mouseTrailSize, 0, 0); err != nil { if err := _SystemParametersInfoW(_SPI_SETMOUSETRAILS, _glfw.platformWindow.mouseTrailSize, 0, 0); err != nil {
return err return err
} }
@ -546,7 +547,7 @@ func (w *Window) maximizeWindowManually() error {
return err return err
} }
exStyle := uint32(s) exStyle := uint32(s)
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
dpi := _GetDpiForWindow(w.platform.handle) dpi := _GetDpiForWindow(w.platform.handle)
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil { if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, dpi); err != nil {
return err return err
@ -588,7 +589,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
// and for a regular window during its initial creation // and for a regular window during its initial creation
switch uMsg { switch uMsg {
case _WM_NCCREATE: case _WM_NCCREATE:
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
cs := (*_CREATESTRUCTW)(unsafe.Pointer(lParam)) cs := (*_CREATESTRUCTW)(unsafe.Pointer(lParam))
wndconfig := (*wndconfig)(cs.lpCreateParams) wndconfig := (*wndconfig)(cs.lpCreateParams)
@ -1062,7 +1063,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
break break
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
dpi = _GetDpiForWindow(window.platform.handle) dpi = _GetDpiForWindow(window.platform.handle)
} }
@ -1122,7 +1123,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
} }
// Adjust the window size to keep the content area size constant // Adjust the window size to keep the content area size constant
if isWindows10CreatorsUpdateOrGreaterWin32() { if winver.IsWindows10CreatorsUpdateOrGreater() {
var source, target _RECT var source, target _RECT
size := (*_SIZE)(unsafe.Pointer(lParam)) size := (*_SIZE)(unsafe.Pointer(lParam))
@ -1146,7 +1147,7 @@ func windowProc(hWnd windows.HWND, uMsg uint32, wParam _WPARAM, lParam _LPARAM)
// Resize windowed mode windows that either permit rescaling or that // Resize windowed mode windows that either permit rescaling or that
// need it to compensate for non-client area scaling // need it to compensate for non-client area scaling
if window.monitor == nil && (window.platform.scaleToMonitor || isWindows10CreatorsUpdateOrGreaterWin32()) { if window.monitor == nil && (window.platform.scaleToMonitor || winver.IsWindows10CreatorsUpdateOrGreater()) {
suggested := (*_RECT)(unsafe.Pointer(lParam)) suggested := (*_RECT)(unsafe.Pointer(lParam))
if err := _SetWindowPos(window.platform.handle, _HWND_TOP, if err := _SetWindowPos(window.platform.handle, _HWND_TOP,
suggested.left, suggested.left,
@ -1244,7 +1245,7 @@ func (w *Window) createNativeWindow(wndconfig *wndconfig, fbconfig *fbconfig) er
handleToWindow[w.platform.handle] = w handleToWindow[w.platform.handle] = w
if !microsoftgdk.IsXbox() && _IsWindows7OrGreater() { if !microsoftgdk.IsXbox() && winver.IsWindows7OrGreater() {
if err := _ChangeWindowMessageFilterEx(w.platform.handle, _WM_DROPFILES, _MSGFLT_ALLOW, nil); err != nil { if err := _ChangeWindowMessageFilterEx(w.platform.handle, _WM_DROPFILES, _MSGFLT_ALLOW, nil); err != nil {
return err return err
} }
@ -1291,7 +1292,7 @@ func (w *Window) createNativeWindow(wndconfig *wndconfig, fbconfig *fbconfig) er
return err return err
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, _GetDpiForWindow(w.platform.handle)); err != nil { if err := _AdjustWindowRectExForDpi(&rect, style, false, exStyle, _GetDpiForWindow(w.platform.handle)); err != nil {
return err return err
} }
@ -1577,7 +1578,7 @@ func (w *Window) platformSetWindowPos(xpos, ypos int) error {
right: int32(xpos), right: int32(xpos),
bottom: int32(ypos), bottom: int32(ypos),
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil { if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err return err
} }
@ -1619,7 +1620,7 @@ func (w *Window) platformSetWindowSize(width, height int) error {
bottom: int32(height), bottom: int32(height),
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil { if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err return err
} }
@ -1688,7 +1689,7 @@ func (w *Window) platformGetWindowFrameSize() (left, top, right, bottom int, err
right: int32(width), right: int32(width),
bottom: int32(height), bottom: int32(height),
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil { if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return 0, 0, 0, 0, err return 0, 0, 0, 0, err
} }
@ -1770,7 +1771,7 @@ func (w *Window) platformSetWindowMonitor(monitor *Monitor, xpos, ypos, width, h
right: int32(xpos + width), right: int32(xpos + width),
bottom: int32(ypos + height), bottom: int32(ypos + height),
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil { if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), false, w.getWindowExStyle(), _GetDpiForWindow(w.platform.handle)); err != nil {
return err return err
} }
@ -1853,7 +1854,7 @@ func (w *Window) platformSetWindowMonitor(monitor *Monitor, xpos, ypos, width, h
right: int32(xpos + width), right: int32(xpos + width),
bottom: int32(ypos + height), bottom: int32(ypos + height),
} }
if isWindows10AnniversaryUpdateOrGreaterWin32() { if winver.IsWindows10AnniversaryUpdateOrGreater() {
if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(), if err := _AdjustWindowRectExForDpi(&rect, w.getWindowStyle(),
false, w.getWindowExStyle(), false, w.getWindowExStyle(),
_GetDpiForWindow(w.platform.handle)); err != nil { _GetDpiForWindow(w.platform.handle)); err != nil {
@ -1926,7 +1927,7 @@ func (w *Window) platformFramebufferTransparent() bool {
return false return false
} }
if !_IsWindowsVistaOrGreater() { if !winver.IsWindowsVistaOrGreater() {
return false return false
} }
@ -1935,7 +1936,7 @@ func (w *Window) platformFramebufferTransparent() bool {
return false return false
} }
if !_IsWindows8OrGreater() { if !winver.IsWindows8OrGreater() {
// HACK: Disable framebuffer transparency on Windows 7 when the // HACK: Disable framebuffer transparency on Windows 7 when the
// colorization color is opaque, because otherwise the window // colorization color is opaque, because otherwise the window
// contents is blended additively with the previous frame instead // contents is blended additively with the previous frame instead

View File

@ -16,7 +16,6 @@ package directx
import ( import (
"fmt" "fmt"
"runtime"
"unsafe" "unsafe"
"golang.org/x/sys/windows" "golang.org/x/sys/windows"
@ -24,13 +23,6 @@ import (
const is64bit = unsafe.Sizeof(uintptr(0)) == 8 const is64bit = unsafe.Sizeof(uintptr(0)) == 8
const (
_VER_BUILDNUMBER = 0x00000004
_VER_GREATER_EQUAL = 3
_VER_MAJORVERSION = 0x00000002
_VER_MINORVERSION = 0x00000001
)
type handleError windows.Handle type handleError windows.Handle
func (h handleError) Error() string { func (h handleError) Error() string {
@ -48,33 +40,13 @@ func boolToUintptr(v bool) uintptr {
return 0 return 0
} }
type _OSVERSIONINFOEXW struct {
dwOSVersionInfoSize uint32
dwMajorVersion uint32
dwMinorVersion uint32
dwBuildNumber uint32
dwPlatformId uint32
szCSDVersion [128]uint16
wServicePackMajor uint16
wServicePackMinor uint16
wSuiteMask uint16
wProductType byte
wReserved byte
}
type _PAPPSTATE_CHANGE_ROUTINE func(quiesced bool, context unsafe.Pointer) uintptr type _PAPPSTATE_CHANGE_ROUTINE func(quiesced bool, context unsafe.Pointer) uintptr
var ( var (
// https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/appnotify/nf-appnotify-registerappstatechangenotification.md // https://github.com/MicrosoftDocs/sdk-api/blob/docs/sdk-api-src/content/appnotify/nf-appnotify-registerappstatechangenotification.md
appnotify = windows.NewLazySystemDLL("API-MS-Win-Core-psm-appnotify-l1-1-0.dll") appnotify = windows.NewLazySystemDLL("API-MS-Win-Core-psm-appnotify-l1-1-0.dll")
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
procRegisterAppStateChangeNotification = appnotify.NewProc("RegisterAppStateChangeNotification") procRegisterAppStateChangeNotification = appnotify.NewProc("RegisterAppStateChangeNotification")
procVerSetConditionMask = kernel32.NewProc("VerSetConditionMask")
procRtlVerifyVersionInfo = ntdll.NewProc("RtlVerifyVersionInfo")
) )
func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, context unsafe.Pointer) (unsafe.Pointer, error) { func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, context unsafe.Pointer) (unsafe.Pointer, error) {
@ -86,45 +58,3 @@ func _RegisterAppStateChangeNotification(routine _PAPPSTATE_CHANGE_ROUTINE, cont
} }
return registration, nil return registration, nil
} }
func _RtlVerifyVersionInfo(versionInfo *_OSVERSIONINFOEXW, typeMask uint32, conditionMask uint64) int32 {
var r uintptr
if is64bit {
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask))
} else {
switch runtime.GOARCH {
case "386":
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask), uintptr(conditionMask>>32))
case "arm":
// Adjust the alignment for ARM.
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), 0, uintptr(conditionMask), uintptr(conditionMask>>32))
default:
panic(fmt.Sprintf("directx: GOARCH=%s is not supported", runtime.GOARCH))
}
}
return int32(r)
}
func _VerSetConditionMask(conditionMask uint64, typeMask uint32, condition byte) uint64 {
if is64bit {
r, _, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(typeMask), uintptr(condition))
return uint64(r)
} else {
r1, r2, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(conditionMask>>32), uintptr(typeMask), uintptr(condition))
return uint64(r1) | (uint64(r2) << 32)
}
}
func isWindows10OrGreaterWin32() bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: 0,
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_BUILDNUMBER
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_BUILDNUMBER, _VER_GREATER_EQUAL)
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}

View File

@ -29,6 +29,7 @@ import (
"github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver" "github.com/hajimehoshi/ebiten/v2/internal/graphicsdriver"
"github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk" "github.com/hajimehoshi/ebiten/v2/internal/microsoftgdk"
"github.com/hajimehoshi/ebiten/v2/internal/winver"
) )
type stencilMode int type stencilMode int
@ -275,7 +276,7 @@ func (g *graphicsInfra) initSwapChain(width, height int, device unsafe.Pointer,
// DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL/DISCARD are not supported for older Windows than 10 or DirectX 12. // DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL/DISCARD are not supported for older Windows than 10 or DirectX 12.
// https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_effect // https://learn.microsoft.com/en-us/windows/win32/api/dxgi/ne-dxgi-dxgi_swap_effect
if !isWindows10OrGreaterWin32() { if !winver.IsWindows10OrGreater() {
desc.SwapEffect = _DXGI_SWAP_EFFECT_SEQUENTIAL desc.SwapEffect = _DXGI_SWAP_EFFECT_SEQUENTIAL
desc.BufferCount = 1 desc.BufferCount = 1
} }

View File

@ -0,0 +1,95 @@
// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package winver
import (
"fmt"
"runtime"
"unsafe"
"golang.org/x/sys/windows"
)
const (
_VER_BUILDNUMBER = 0x00000004
_VER_GREATER_EQUAL = 3
_VER_MAJORVERSION = 0x00000002
_VER_MINORVERSION = 0x00000001
_VER_SERVICEPACKMAJOR = 0x00000020
_WIN32_WINNT_VISTA = 0x0600
_WIN32_WINNT_WIN7 = 0x0601
_WIN32_WINNT_WIN8 = 0x0602
_WIN32_WINNT_WINBLUE = 0x0603
_WIN32_WINNT_WINXP = 0x0501
)
type _OSVERSIONINFOEXW struct {
dwOSVersionInfoSize uint32
dwMajorVersion uint32
dwMinorVersion uint32
dwBuildNumber uint32
dwPlatformId uint32
szCSDVersion [128]uint16
wServicePackMajor uint16
wServicePackMinor uint16
wSuiteMask uint16
wProductType byte
wReserved byte
}
func _HIBYTE(wValue uint16) byte {
return byte(wValue >> 8)
}
func _LOBYTE(wValue uint16) byte {
return byte(wValue)
}
var (
kernel32 = windows.NewLazySystemDLL("kernel32.dll")
ntdll = windows.NewLazySystemDLL("ntdll.dll")
procVerSetConditionMask = kernel32.NewProc("VerSetConditionMask")
procRtlVerifyVersionInfo = ntdll.NewProc("RtlVerifyVersionInfo")
)
func _RtlVerifyVersionInfo(versionInfo *_OSVERSIONINFOEXW, typeMask uint32, conditionMask uint64) int32 {
var r uintptr
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask))
} else {
switch runtime.GOARCH {
case "386":
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), uintptr(conditionMask), uintptr(conditionMask>>32))
case "arm":
// Adjust the alignment for ARM.
r, _, _ = procRtlVerifyVersionInfo.Call(uintptr(unsafe.Pointer(versionInfo)), uintptr(typeMask), 0, uintptr(conditionMask), uintptr(conditionMask>>32))
default:
panic(fmt.Sprintf("goglfw: GOARCH=%s is not supported", runtime.GOARCH))
}
}
return int32(r)
}
func _VerSetConditionMask(conditionMask uint64, typeMask uint32, condition byte) uint64 {
if unsafe.Sizeof(uintptr(0)) == unsafe.Sizeof(uint64(0)) {
r, _, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(typeMask), uintptr(condition))
return uint64(r)
} else {
r1, r2, _ := procVerSetConditionMask.Call(uintptr(conditionMask), uintptr(conditionMask>>32), uintptr(typeMask), uintptr(condition))
return uint64(r1) | (uint64(r2) << 32)
}
}

View File

@ -0,0 +1,87 @@
// Copyright 2023 The Ebitengine Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package winver
import (
"unsafe"
)
func isWindowsVersionOrGreater(major, minor, sp uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: uint32(major),
dwMinorVersion: uint32(minor),
wServicePackMajor: sp,
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_SERVICEPACKMAJOR
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_SERVICEPACKMAJOR, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func isWindows10BuildOrGreater(build uint16) bool {
osvi := _OSVERSIONINFOEXW{
dwMajorVersion: 10,
dwMinorVersion: 0,
dwBuildNumber: uint32(build),
}
osvi.dwOSVersionInfoSize = uint32(unsafe.Sizeof(osvi))
var mask uint32 = _VER_MAJORVERSION | _VER_MINORVERSION | _VER_BUILDNUMBER
cond := _VerSetConditionMask(0, _VER_MAJORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_MINORVERSION, _VER_GREATER_EQUAL)
cond = _VerSetConditionMask(cond, _VER_BUILDNUMBER, _VER_GREATER_EQUAL)
// HACK: Use RtlVerifyVersionInfo instead of VerifyVersionInfoW as the
// latter lies unless the user knew to embed a non-default manifest
// announcing support for Windows 10 via supportedOS GUID
return _RtlVerifyVersionInfo(&osvi, mask, cond) == 0
}
func IsWindowsXPOrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WINXP)), uint16(_LOBYTE(_WIN32_WINNT_WINXP)), 0)
}
func IsWindowsVistaOrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_VISTA)), uint16(_LOBYTE(_WIN32_WINNT_VISTA)), 0)
}
func IsWindows7OrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WIN7)), uint16(_LOBYTE(_WIN32_WINNT_WIN7)), 0)
}
func IsWindows8OrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WIN8)), uint16(_LOBYTE(_WIN32_WINNT_WIN8)), 0)
}
func IsWindows8Point1OrGreater() bool {
return isWindowsVersionOrGreater(uint16(_HIBYTE(_WIN32_WINNT_WINBLUE)), uint16(_LOBYTE(_WIN32_WINNT_WINBLUE)), 0)
}
func IsWindows10OrGreater() bool {
return isWindows10BuildOrGreater(0)
}
func IsWindows10AnniversaryUpdateOrGreater() bool {
return isWindows10BuildOrGreater(14393)
}
func IsWindows10CreatorsUpdateOrGreater() bool {
return isWindows10BuildOrGreater(15063)
}