Operating System
What feature would you like to be added?
A method to expose the game window's handle to the user once the game window has been created, potentially with a documented point in the lifecycle where it is guaranteed to be available.
Why is this needed?
Getting the handle for the game window to set DWM attributes for window styling currently requires brittle mechanisms to query the Win32 APIs. You can enumerate the windows and either look up the game window handle by its title or its PID but requires a good bit of boilerplate that is easy to mess up. Additionally, you must use arbitrary delays to correctly style the game window after it is created. Here is example code to grab a handle:
package windows
import (
"fmt"
"lock-on-labs/slip-hop/internal/window/theme/windows/backdrop"
"os"
"syscall"
"time"
"unsafe"
"golang.org/x/sys/windows"
)
var (
user32 = syscall.NewLazyDLL("user32.dll")
procEnumWindows = user32.NewProc("EnumWindows")
procGetWindowThreadProcessId = user32.NewProc("GetWindowThreadProcessId")
procIsWindowVisible = user32.NewProc("IsWindowVisible")
)
const dwmwaSystemBackdropType = 38
func findWindowByProcessId(myPid uint32) windows.HWND {
var target windows.HWND
cb := syscall.NewCallback(func(hwnd, lParam uintptr) uintptr {
var pid uint32
procGetWindowThreadProcessId.Call(hwnd, uintptr(unsafe.Pointer(&pid)))
if myPid == pid {
ret, _, _ := procIsWindowVisible.Call(hwnd)
if ret != 0 {
target = windows.HWND(hwnd)
return 0
}
}
return 1
})
procEnumWindows.Call(cb, 0)
return target
}
func ApplyBackdrop(backdrop backdrop.Backdrop) {
pid := uint32(os.Getpid())
var window windows.HWND
// time out if we don't fetch the window within 5 seconds
deadline := time.Now().Add(5 * time.Second)
for window == 0 {
if time.Now().After(deadline) {
return
}
window = findWindowByProcessId(pid)
time.Sleep(10 * time.Millisecond)
}
darkMode := uint32(1) // dark mode
if err := windows.DwmSetWindowAttribute(window,
windows.DWMWA_USE_IMMERSIVE_DARK_MODE,
unsafe.Pointer(&darkMode),
uint32(unsafe.Sizeof(darkMode)),
); err != nil {
fmt.Printf("DWMWA_USE_IMMERSIVE_DARK_MODE failed: %v\n", err)
}
if err := windows.DwmSetWindowAttribute(window,
dwmwaSystemBackdropType,
unsafe.Pointer(&backdrop),
uint32(unsafe.Sizeof(backdrop)),
); err != nil {
fmt.Printf("DWMWA_SYSTEMBACKDROP_TYPE failed: %v\n", err)
}
}
Invoking it from the root game creation:
func main() {
ebiten.SetWindowTitle(title)
ebiten.SetWindowSize(windowWidth, windowHeight)
if runtime.GOOS == "windows" {
go theme.ApplyBackdrop(theme.MainWindow)
}
g := game.NewGame()
err := ebiten.RunGame(&g)
if err != nil {
log.Fatal(err)
}
}
Ideally, advanced users could be able to get a pointer to the game window with a lifecycle guarantee without enumerating over windows or by using arbitrary delays.
Operating System
What feature would you like to be added?
A method to expose the game window's handle to the user once the game window has been created, potentially with a documented point in the lifecycle where it is guaranteed to be available.
Why is this needed?
Getting the handle for the game window to set DWM attributes for window styling currently requires brittle mechanisms to query the Win32 APIs. You can enumerate the windows and either look up the game window handle by its title or its PID but requires a good bit of boilerplate that is easy to mess up. Additionally, you must use arbitrary delays to correctly style the game window after it is created. Here is example code to grab a handle:
Invoking it from the root game creation:
Ideally, advanced users could be able to get a pointer to the game window with a lifecycle guarantee without enumerating over windows or by using arbitrary delays.