From 06a2228798dc17968fe6a42329ccd4d022616551 Mon Sep 17 00:00:00 2001 From: Elias Naur Date: Fri, 29 Nov 2019 22:12:33 +0100 Subject: [PATCH] app/internal/windows: split out Windows syscalls from package window Signed-off-by: Elias Naur --- app/internal/window/os_windows.go | 667 ++++++------------------------ app/internal/windows/windows.go | 450 ++++++++++++++++++++ 2 files changed, 566 insertions(+), 551 deletions(-) create mode 100644 app/internal/windows/windows.go diff --git a/app/internal/window/os_windows.go b/app/internal/window/os_windows.go index d172d55f..d7b781a1 100644 --- a/app/internal/window/os_windows.go +++ b/app/internal/window/os_windows.go @@ -4,7 +4,6 @@ package window import ( "errors" - "fmt" "image" "runtime" "sync" @@ -14,6 +13,8 @@ import ( syscall "golang.org/x/sys/windows" + "gioui.org/app/internal/windows" + "gioui.org/f32" "gioui.org/io/key" "gioui.org/io/pointer" @@ -22,39 +23,6 @@ import ( var winMap = make(map[syscall.Handle]*window) -type rect struct { - left, top, right, bottom int32 -} - -type wndClassEx struct { - cbSize uint32 - style uint32 - lpfnWndProc uintptr - cnClsExtra int32 - cbWndExtra int32 - hInstance syscall.Handle - hIcon syscall.Handle - hCursor syscall.Handle - hbrBackground syscall.Handle - lpszMenuName *uint16 - lpszClassName *uint16 - hIconSm syscall.Handle -} - -type msg struct { - hwnd syscall.Handle - message uint32 - wParam uintptr - lParam uintptr - time uint32 - pt point - lPrivate uint32 -} - -type point struct { - x, y int32 -} - type window struct { hwnd syscall.Handle hdc syscall.Handle @@ -69,134 +37,7 @@ type window struct { animating bool } -const ( - _CS_HREDRAW = 0x0002 - _CS_VREDRAW = 0x0001 - _CS_OWNDC = 0x0020 - - _CW_USEDEFAULT = -2147483648 - - _IDC_ARROW = 32512 - - _INFINITE = 0xFFFFFFFF - - _LOGPIXELSX = 88 - - _MDT_EFFECTIVE_DPI = 0 - - _MONITOR_DEFAULTTOPRIMARY = 1 - - _SIZE_MAXIMIZED = 2 - _SIZE_MINIMIZED = 1 - _SIZE_RESTORED = 0 - - _SW_SHOWDEFAULT = 10 - - _USER_TIMER_MINIMUM = 0x0000000A - - _VK_CONTROL = 0x11 - _VK_LWIN = 0x5B - _VK_MENU = 0x12 - _VK_RWIN = 0x5C - _VK_SHIFT = 0x10 - - _VK_BACK = 0x08 - _VK_DELETE = 0x2e - _VK_DOWN = 0x28 - _VK_END = 0x23 - _VK_ESCAPE = 0x1b - _VK_HOME = 0x24 - _VK_LEFT = 0x25 - _VK_NEXT = 0x22 - _VK_PRIOR = 0x21 - _VK_RIGHT = 0x27 - _VK_RETURN = 0x0d - _VK_SPACE = 0x20 - _VK_TAB = 0x09 - _VK_UP = 0x26 - - _VK_F1 = 0x70 - _VK_F2 = 0x71 - _VK_F3 = 0x72 - _VK_F4 = 0x73 - _VK_F5 = 0x74 - _VK_F6 = 0x75 - _VK_F7 = 0x76 - _VK_F8 = 0x77 - _VK_F9 = 0x78 - _VK_F10 = 0x79 - _VK_F11 = 0x7A - _VK_F12 = 0x7B - - _VK_OEM_1 = 0xba - _VK_OEM_PLUS = 0xbb - _VK_OEM_COMMA = 0xbc - _VK_OEM_MINUS = 0xbd - _VK_OEM_PERIOD = 0xbe - _VK_OEM_2 = 0xbf - _VK_OEM_3 = 0xc0 - _VK_OEM_4 = 0xdb - _VK_OEM_5 = 0xdc - _VK_OEM_6 = 0xdd - _VK_OEM_7 = 0xde - _VK_OEM_102 = 0xe2 - - _UNICODE_NOCHAR = 65535 - - _WM_CANCELMODE = 0x001F - _WM_CHAR = 0x0102 - _WM_CREATE = 0x0001 - _WM_DPICHANGED = 0x02E0 - _WM_DESTROY = 0x0002 - _WM_ERASEBKGND = 0x0014 - _WM_KEYDOWN = 0x0100 - _WM_KEYUP = 0x0101 - _WM_LBUTTONDOWN = 0x0201 - _WM_LBUTTONUP = 0x0202 - _WM_MBUTTONDOWN = 0x0207 - _WM_MBUTTONUP = 0x0208 - _WM_MOUSEMOVE = 0x0200 - _WM_MOUSEWHEEL = 0x020A - _WM_PAINT = 0x000F - _WM_QUIT = 0x0012 - _WM_SETFOCUS = 0x0007 - _WM_KILLFOCUS = 0x0008 - _WM_SHOWWINDOW = 0x0018 - _WM_SIZE = 0x0005 - _WM_SYSKEYDOWN = 0x0104 - _WM_RBUTTONDOWN = 0x0204 - _WM_RBUTTONUP = 0x0205 - _WM_TIMER = 0x0113 - _WM_UNICHAR = 0x0109 - _WM_USER = 0x0400 - - _WS_CLIPCHILDREN = 0x00010000 - _WS_CLIPSIBLINGS = 0x04000000 - _WS_VISIBLE = 0x10000000 - _WS_OVERLAPPED = 0x00000000 - _WS_OVERLAPPEDWINDOW = _WS_OVERLAPPED | _WS_CAPTION | _WS_SYSMENU | _WS_THICKFRAME | - _WS_MINIMIZEBOX | _WS_MAXIMIZEBOX - _WS_CAPTION = 0x00C00000 - _WS_SYSMENU = 0x00080000 - _WS_THICKFRAME = 0x00040000 - _WS_MINIMIZEBOX = 0x00020000 - _WS_MAXIMIZEBOX = 0x00010000 - - _WS_EX_APPWINDOW = 0x00040000 - _WS_EX_WINDOWEDGE = 0x00000100 - - _QS_ALLINPUT = 0x04FF - - _MWMO_WAITALL = 0x0001 - _MWMO_INPUTAVAILABLE = 0x0004 - - _WAIT_OBJECT_0 = 0 - - _PM_REMOVE = 0x0001 - _PM_NOREMOVE = 0x0000 -) - -const _WM_REDRAW = _WM_USER + 0 +const _WM_REDRAW = windows.WM_USER + 0 var onceMu sync.Mutex var mainDone = make(chan struct{}) @@ -227,9 +68,9 @@ func NewWindow(window Callbacks, opts *Options) error { w.w = window w.w.SetDriver(w) defer w.w.Event(system.DestroyEvent{}) - showWindow(w.hwnd, _SW_SHOWDEFAULT) - setForegroundWindow(w.hwnd) - setFocus(w.hwnd) + windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT) + windows.SetForegroundWindow(w.hwnd) + windows.SetFocus(w.hwnd) if err := w.loop(); err != nil { panic(err) } @@ -239,42 +80,42 @@ func NewWindow(window Callbacks, opts *Options) error { } func createNativeWindow(opts *Options) (*window, error) { - setProcessDPIAware() + windows.SetProcessDPIAware() cfg := configForDC() - hInst, err := getModuleHandle() + hInst, err := windows.GetModuleHandle() if err != nil { return nil, err } - curs, err := loadCursor(_IDC_ARROW) + curs, err := windows.LoadCursor(windows.IDC_ARROW) if err != nil { return nil, err } - wcls := wndClassEx{ - cbSize: uint32(unsafe.Sizeof(wndClassEx{})), - style: _CS_HREDRAW | _CS_VREDRAW | _CS_OWNDC, - lpfnWndProc: syscall.NewCallback(windowProc), - hInstance: hInst, - hCursor: curs, - lpszClassName: syscall.StringToUTF16Ptr("GioWindow"), + wcls := windows.WndClassEx{ + CbSize: uint32(unsafe.Sizeof(windows.WndClassEx{})), + Style: windows.CS_HREDRAW | windows.CS_VREDRAW | windows.CS_OWNDC, + LpfnWndProc: syscall.NewCallback(windowProc), + HInstance: hInst, + HCursor: curs, + LpszClassName: syscall.StringToUTF16Ptr("GioWindow"), } - cls, err := registerClassEx(&wcls) + cls, err := windows.RegisterClassEx(&wcls) if err != nil { return nil, err } - wr := rect{ - right: int32(cfg.Px(opts.Width)), - bottom: int32(cfg.Px(opts.Height)), + wr := windows.Rect{ + Right: int32(cfg.Px(opts.Width)), + Bottom: int32(cfg.Px(opts.Height)), } - dwStyle := uint32(_WS_OVERLAPPEDWINDOW) - dwExStyle := uint32(_WS_EX_APPWINDOW | _WS_EX_WINDOWEDGE) - adjustWindowRectEx(&wr, dwStyle, 0, dwExStyle) - hwnd, err := createWindowEx(dwExStyle, + dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW) + dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE) + windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle) + hwnd, err := windows.CreateWindowEx(dwExStyle, cls, opts.Title, - dwStyle|_WS_CLIPSIBLINGS|_WS_CLIPCHILDREN, - _CW_USEDEFAULT, _CW_USEDEFAULT, - wr.right-wr.left, - wr.bottom-wr.top, + dwStyle|windows.WS_CLIPSIBLINGS|windows.WS_CLIPCHILDREN, + windows.CW_USEDEFAULT, windows.CW_USEDEFAULT, + wr.Right-wr.Left, + wr.Bottom-wr.Top, 0, 0, hInst, @@ -285,7 +126,7 @@ func createNativeWindow(opts *Options) (*window, error) { w := &window{ hwnd: hwnd, } - w.hdc, err = getDC(hwnd) + w.hdc, err = windows.GetDC(hwnd) if err != nil { return nil, err } @@ -295,86 +136,86 @@ func createNativeWindow(opts *Options) (*window, error) { func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr { w := winMap[hwnd] switch msg { - case _WM_UNICHAR: - if wParam == _UNICODE_NOCHAR { + case windows.WM_UNICHAR: + if wParam == windows.UNICODE_NOCHAR { // Tell the system that we accept WM_UNICHAR messages. return 1 } fallthrough - case _WM_CHAR: + case windows.WM_CHAR: if r := rune(wParam); unicode.IsPrint(r) { w.w.Event(key.EditEvent{Text: string(r)}) } // The message is processed. return 1 - case _WM_DPICHANGED: + case windows.WM_DPICHANGED: // Let Windows know we're prepared for runtime DPI changes. return 1 - case _WM_ERASEBKGND: + case windows.WM_ERASEBKGND: // Avoid flickering between GPU content and background color. return 1 - case _WM_KEYDOWN, _WM_SYSKEYDOWN: + case windows.WM_KEYDOWN, windows.WM_SYSKEYDOWN: if n, ok := convertKeyCode(wParam); ok { w.w.Event(key.Event{Name: n, Modifiers: getModifiers()}) } - case _WM_LBUTTONDOWN: + case windows.WM_LBUTTONDOWN: w.pointerButton(pointer.ButtonLeft, true, lParam, getModifiers()) - case _WM_LBUTTONUP: + case windows.WM_LBUTTONUP: w.pointerButton(pointer.ButtonLeft, false, lParam, getModifiers()) - case _WM_RBUTTONDOWN: + case windows.WM_RBUTTONDOWN: w.pointerButton(pointer.ButtonRight, true, lParam, getModifiers()) - case _WM_RBUTTONUP: + case windows.WM_RBUTTONUP: w.pointerButton(pointer.ButtonRight, false, lParam, getModifiers()) - case _WM_MBUTTONDOWN: + case windows.WM_MBUTTONDOWN: w.pointerButton(pointer.ButtonMiddle, true, lParam, getModifiers()) - case _WM_MBUTTONUP: + case windows.WM_MBUTTONUP: w.pointerButton(pointer.ButtonMiddle, false, lParam, getModifiers()) - case _WM_CANCELMODE: + case windows.WM_CANCELMODE: w.w.Event(pointer.Event{ Type: pointer.Cancel, }) - case _WM_SETFOCUS: + case windows.WM_SETFOCUS: w.w.Event(key.FocusEvent{Focus: true}) - case _WM_KILLFOCUS: + case windows.WM_KILLFOCUS: w.w.Event(key.FocusEvent{Focus: false}) - case _WM_MOUSEMOVE: + case windows.WM_MOUSEMOVE: x, y := coordsFromlParam(lParam) p := f32.Point{X: float32(x), Y: float32(y)} w.w.Event(pointer.Event{ Type: pointer.Move, Source: pointer.Mouse, Position: p, - Time: getMessageTime(), + Time: windows.GetMessageTime(), }) - case _WM_MOUSEWHEEL: + case windows.WM_MOUSEWHEEL: w.scrollEvent(wParam, lParam) - case _WM_DESTROY: + case windows.WM_DESTROY: w.dead = true - case _WM_PAINT: + case windows.WM_PAINT: w.draw(true) - case _WM_SIZE: + case windows.WM_SIZE: switch wParam { - case _SIZE_MINIMIZED: + case windows.SIZE_MINIMIZED: w.setStage(system.StagePaused) - case _SIZE_MAXIMIZED, _SIZE_RESTORED: + case windows.SIZE_MAXIMIZED, windows.SIZE_RESTORED: w.setStage(system.StageRunning) } } - return defWindowProc(hwnd, msg, wParam, lParam) + return windows.DefWindowProc(hwnd, msg, wParam, lParam) } func getModifiers() key.Modifiers { var kmods key.Modifiers - if getKeyState(_VK_LWIN)&0x1000 != 0 || getKeyState(_VK_RWIN)&0x1000 != 0 { + if windows.GetKeyState(windows.VK_LWIN)&0x1000 != 0 || windows.GetKeyState(windows.VK_RWIN)&0x1000 != 0 { kmods |= key.ModSuper } - if getKeyState(_VK_MENU)&0x1000 != 0 { + if windows.GetKeyState(windows.VK_MENU)&0x1000 != 0 { kmods |= key.ModAlt } - if getKeyState(_VK_CONTROL)&0x1000 != 0 { + if windows.GetKeyState(windows.VK_CONTROL)&0x1000 != 0 { kmods |= key.ModCtrl } - if getKeyState(_VK_SHIFT)&0x1000 != 0 { + if windows.GetKeyState(windows.VK_SHIFT)&0x1000 != 0 { kmods |= key.ModShift } return kmods @@ -385,14 +226,14 @@ func (w *window) pointerButton(btn pointer.Buttons, press bool, lParam uintptr, if press { typ = pointer.Press if w.pointerBtns == 0 { - setCapture(w.hwnd) + windows.SetCapture(w.hwnd) } w.pointerBtns |= btn } else { typ = pointer.Release w.pointerBtns &^= btn if w.pointerBtns == 0 { - releaseCapture() + windows.ReleaseCapture() } } x, y := coordsFromlParam(lParam) @@ -402,7 +243,7 @@ func (w *window) pointerButton(btn pointer.Buttons, press bool, lParam uintptr, Source: pointer.Mouse, Position: p, Buttons: w.pointerBtns, - Time: getMessageTime(), + Time: windows.GetMessageTime(), Modifiers: kmods, }) } @@ -417,37 +258,37 @@ func (w *window) scrollEvent(wParam, lParam uintptr) { x, y := coordsFromlParam(lParam) // The WM_MOUSEWHEEL coordinates are in screen coordinates, in contrast // to other mouse events. - np := point{x: int32(x), y: int32(y)} - screenToClient(w.hwnd, &np) - p := f32.Point{X: float32(np.x), Y: float32(np.y)} + np := windows.Point{X: int32(x), Y: int32(y)} + windows.ScreenToClient(w.hwnd, &np) + p := f32.Point{X: float32(np.X), Y: float32(np.Y)} dist := float32(int16(wParam >> 16)) w.w.Event(pointer.Event{ Type: pointer.Move, Source: pointer.Mouse, Position: p, Scroll: f32.Point{Y: -dist}, - Time: getMessageTime(), + Time: windows.GetMessageTime(), }) } // Adapted from https://blogs.msdn.microsoft.com/oldnewthing/20060126-00/?p=32513/ func (w *window) loop() error { - msg := new(msg) + msg := new(windows.Msg) for !w.dead { w.mu.Lock() anim := w.animating w.mu.Unlock() - if anim && !peekMessage(msg, w.hwnd, 0, 0, _PM_NOREMOVE) { + if anim && !windows.PeekMessage(msg, w.hwnd, 0, 0, windows.PM_NOREMOVE) { w.draw(false) continue } - getMessage(msg, w.hwnd, 0, 0) - if msg.message == _WM_QUIT { - postQuitMessage(msg.wParam) + windows.GetMessage(msg, w.hwnd, 0, 0) + if msg.Message == windows.WM_QUIT { + windows.PostQuitMessage(msg.WParam) break } - translateMessage(msg) - dispatchMessage(msg) + windows.TranslateMessage(msg) + windows.DispatchMessage(msg) } return nil } @@ -462,7 +303,7 @@ func (w *window) SetAnimating(anim bool) { } func (w *window) postRedraw() { - if err := postMessage(w.hwnd, _WM_REDRAW, 0, 0); err != nil { + if err := windows.PostMessage(w.hwnd, _WM_REDRAW, 0, 0); err != nil { panic(err) } } @@ -473,10 +314,10 @@ func (w *window) setStage(s system.Stage) { } func (w *window) draw(sync bool) { - var r rect - getClientRect(w.hwnd, &r) - w.width = int(r.right - r.left) - w.height = int(r.bottom - r.top) + var r windows.Rect + windows.GetClientRect(w.hwnd, &r) + w.width = int(r.Right - r.Left) + w.height = int(r.Bottom - r.Top) cfg := configForDC() cfg.now = time.Now() w.w.Event(FrameEvent{ @@ -493,11 +334,11 @@ func (w *window) draw(sync bool) { func (w *window) destroy() { if w.hdc != 0 { - releaseDC(w.hdc) + windows.ReleaseDC(w.hdc) w.hdc = 0 } if w.hwnd != 0 { - destroyWindow(w.hwnd) + windows.DestroyWindow(w.hwnd) w.hwnd = 0 } } @@ -518,79 +359,79 @@ func convertKeyCode(code uintptr) (string, bool) { } var r string switch code { - case _VK_ESCAPE: + case windows.VK_ESCAPE: r = key.NameEscape - case _VK_LEFT: + case windows.VK_LEFT: r = key.NameLeftArrow - case _VK_RIGHT: + case windows.VK_RIGHT: r = key.NameRightArrow - case _VK_RETURN: + case windows.VK_RETURN: r = key.NameReturn - case _VK_UP: + case windows.VK_UP: r = key.NameUpArrow - case _VK_DOWN: + case windows.VK_DOWN: r = key.NameDownArrow - case _VK_HOME: + case windows.VK_HOME: r = key.NameHome - case _VK_END: + case windows.VK_END: r = key.NameEnd - case _VK_BACK: + case windows.VK_BACK: r = key.NameDeleteBackward - case _VK_DELETE: + case windows.VK_DELETE: r = key.NameDeleteForward - case _VK_PRIOR: + case windows.VK_PRIOR: r = key.NamePageUp - case _VK_NEXT: + case windows.VK_NEXT: r = key.NamePageDown - case _VK_F1: + case windows.VK_F1: r = "F1" - case _VK_F2: + case windows.VK_F2: r = "F2" - case _VK_F3: + case windows.VK_F3: r = "F3" - case _VK_F4: + case windows.VK_F4: r = "F4" - case _VK_F5: + case windows.VK_F5: r = "F5" - case _VK_F6: + case windows.VK_F6: r = "F6" - case _VK_F7: + case windows.VK_F7: r = "F7" - case _VK_F8: + case windows.VK_F8: r = "F8" - case _VK_F9: + case windows.VK_F9: r = "F9" - case _VK_F10: + case windows.VK_F10: r = "F10" - case _VK_F11: + case windows.VK_F11: r = "F11" - case _VK_F12: + case windows.VK_F12: r = "F12" - case _VK_TAB: + case windows.VK_TAB: r = key.NameTab - case _VK_SPACE: + case windows.VK_SPACE: r = "Space" - case _VK_OEM_1: + case windows.VK_OEM_1: r = ";" - case _VK_OEM_PLUS: + case windows.VK_OEM_PLUS: r = "+" - case _VK_OEM_COMMA: + case windows.VK_OEM_COMMA: r = "," - case _VK_OEM_MINUS: + case windows.VK_OEM_MINUS: r = "-" - case _VK_OEM_PERIOD: + case windows.VK_OEM_PERIOD: r = "." - case _VK_OEM_2: + case windows.VK_OEM_2: r = "/" - case _VK_OEM_3: + case windows.VK_OEM_3: r = "`" - case _VK_OEM_4: + case windows.VK_OEM_4: r = "[" - case _VK_OEM_5, _VK_OEM_102: + case windows.VK_OEM_5, windows.VK_OEM_102: r = "\\" - case _VK_OEM_6: + case windows.VK_OEM_6: r = "]" - case _VK_OEM_7: + case windows.VK_OEM_7: r = "'" default: return "", false @@ -599,7 +440,7 @@ func convertKeyCode(code uintptr) (string, bool) { } func configForDC() config { - dpi := getSystemDPI() + dpi := windows.GetSystemDPI() const inchPrDp = 1.0 / 96.0 ppdp := float32(dpi) * inchPrDp return config{ @@ -607,279 +448,3 @@ func configForDC() config { pxPerSp: ppdp, } } - -var ( - kernel32 = syscall.NewLazySystemDLL("kernel32.dll") - _GetModuleHandleW = kernel32.NewProc("GetModuleHandleW") - - user32 = syscall.NewLazySystemDLL("user32.dll") - _AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx") - _CallMsgFilter = user32.NewProc("CallMsgFilterW") - _CreateWindowEx = user32.NewProc("CreateWindowExW") - _DefWindowProc = user32.NewProc("DefWindowProcW") - _DestroyWindow = user32.NewProc("DestroyWindow") - _DispatchMessage = user32.NewProc("DispatchMessageW") - _GetClientRect = user32.NewProc("GetClientRect") - _GetDC = user32.NewProc("GetDC") - _GetKeyState = user32.NewProc("GetKeyState") - _GetMessage = user32.NewProc("GetMessageW") - _GetMessageTime = user32.NewProc("GetMessageTime") - _KillTimer = user32.NewProc("KillTimer") - _LoadCursor = user32.NewProc("LoadCursorW") - _MonitorFromPoint = user32.NewProc("MonitorFromPoint") - _MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx") - _PeekMessage = user32.NewProc("PeekMessageW") - _PostMessage = user32.NewProc("PostMessageW") - _PostQuitMessage = user32.NewProc("PostQuitMessage") - _ReleaseCapture = user32.NewProc("ReleaseCapture") - _RegisterClassExW = user32.NewProc("RegisterClassExW") - _ReleaseDC = user32.NewProc("ReleaseDC") - _ScreenToClient = user32.NewProc("ScreenToClient") - _ShowWindow = user32.NewProc("ShowWindow") - _SetCapture = user32.NewProc("SetCapture") - _SetForegroundWindow = user32.NewProc("SetForegroundWindow") - _SetFocus = user32.NewProc("SetFocus") - _SetProcessDPIAware = user32.NewProc("SetProcessDPIAware") - _SetTimer = user32.NewProc("SetTimer") - _TranslateMessage = user32.NewProc("TranslateMessage") - _UnregisterClass = user32.NewProc("UnregisterClassW") - _UpdateWindow = user32.NewProc("UpdateWindow") - - shcore = syscall.NewLazySystemDLL("shcore") - _GetDpiForMonitor = shcore.NewProc("GetDpiForMonitor") - - gdi32 = syscall.NewLazySystemDLL("gdi32") - _GetDeviceCaps = gdi32.NewProc("GetDeviceCaps") -) - -func getModuleHandle() (syscall.Handle, error) { - h, _, err := _GetModuleHandleW.Call(uintptr(0)) - if h == 0 { - return 0, fmt.Errorf("GetModuleHandleW failed: %v", err) - } - return syscall.Handle(h), nil -} - -func adjustWindowRectEx(r *rect, dwStyle uint32, bMenu int, dwExStyle uint32) { - _AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle)) - issue34474KeepAlive(r) -} - -func callMsgFilter(m *msg, nCode uintptr) bool { - r, _, _ := _CallMsgFilter.Call(uintptr(unsafe.Pointer(m)), nCode) - issue34474KeepAlive(m) - return r != 0 -} - -func createWindowEx(dwExStyle uint32, lpClassName uint16, lpWindowName string, dwStyle uint32, x, y, w, h int32, hWndParent, hMenu, hInstance syscall.Handle, lpParam uintptr) (syscall.Handle, error) { - wname := syscall.StringToUTF16Ptr(lpWindowName) - hwnd, _, err := _CreateWindowEx.Call( - uintptr(dwExStyle), - uintptr(lpClassName), - uintptr(unsafe.Pointer(wname)), - uintptr(dwStyle), - uintptr(x), uintptr(y), - uintptr(w), uintptr(h), - uintptr(hWndParent), - uintptr(hMenu), - uintptr(hInstance), - uintptr(lpParam)) - issue34474KeepAlive(wname) - if hwnd == 0 { - return 0, fmt.Errorf("CreateWindowEx failed: %v", err) - } - return syscall.Handle(hwnd), nil -} - -func defWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr { - r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam) - return r -} - -func destroyWindow(hwnd syscall.Handle) { - _DestroyWindow.Call(uintptr(hwnd)) -} - -func dispatchMessage(m *msg) { - _DispatchMessage.Call(uintptr(unsafe.Pointer(m))) - issue34474KeepAlive(m) -} - -func getClientRect(hwnd syscall.Handle, r *rect) { - _GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r))) - issue34474KeepAlive(r) -} - -func getDC(hwnd syscall.Handle) (syscall.Handle, error) { - hdc, _, err := _GetDC.Call(uintptr(hwnd)) - if hdc == 0 { - return 0, fmt.Errorf("GetDC failed: %v", err) - } - return syscall.Handle(hdc), nil -} - -func getDeviceCaps(hdc syscall.Handle, index int32) int { - c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index)) - return int(c) -} - -func getDpiForMonitor(hmonitor syscall.Handle, dpiType uint32) int { - var dpiX, dpiY uintptr - _GetDpiForMonitor.Call(uintptr(hmonitor), uintptr(dpiType), uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY))) - return int(dpiX) -} - -// getSystemDPI returns the effective DPI of the system. -func getSystemDPI() int { - // Check for GetDpiForMonitor, introduced in Windows 8.1. - if _GetDpiForMonitor.Find() == nil { - hmon := monitorFromPoint(point{}, _MONITOR_DEFAULTTOPRIMARY) - return getDpiForMonitor(hmon, _MDT_EFFECTIVE_DPI) - } else { - // Fall back to the physical device DPI. - screenDC, err := getDC(0) - if err != nil { - return 96 - } - defer releaseDC(screenDC) - return getDeviceCaps(screenDC, _LOGPIXELSX) - } -} - -func getKeyState(nVirtKey int32) int16 { - c, _, _ := _GetKeyState.Call(uintptr(nVirtKey)) - return int16(c) -} - -func getMessage(m *msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax uint32) int32 { - r, _, _ := _GetMessage.Call(uintptr(unsafe.Pointer(m)), - uintptr(hwnd), - uintptr(wMsgFilterMin), - uintptr(wMsgFilterMax)) - issue34474KeepAlive(m) - return int32(r) -} - -func getMessageTime() time.Duration { - r, _, _ := _GetMessageTime.Call() - return time.Duration(r) * time.Millisecond -} - -func killTimer(hwnd syscall.Handle, nIDEvent uintptr) error { - r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0) - if r == 0 { - return fmt.Errorf("KillTimer failed: %v", err) - } - return nil -} - -func loadCursor(curID uint16) (syscall.Handle, error) { - h, _, err := _LoadCursor.Call(0, uintptr(curID)) - if h == 0 { - return 0, fmt.Errorf("LoadCursorW failed: %v", err) - } - return syscall.Handle(h), nil -} - -func monitorFromPoint(pt point, flags uint32) syscall.Handle { - r, _, _ := _MonitorFromPoint.Call(uintptr(pt.x), uintptr(pt.y), uintptr(flags)) - return syscall.Handle(r) -} - -func msgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask, flags uint32) (uint32, error) { - r, _, err := _MsgWaitForMultipleObjectsEx.Call(uintptr(nCount), pHandles, uintptr(millis), uintptr(mask), uintptr(flags)) - res := uint32(r) - if res == 0xFFFFFFFF { - return 0, fmt.Errorf("MsgWaitForMultipleObjectsEx failed: %v", err) - } - return res, nil -} - -func peekMessage(m *msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool { - r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg)) - issue34474KeepAlive(m) - return r != 0 -} - -func postQuitMessage(exitCode uintptr) { - _PostQuitMessage.Call(exitCode) -} - -func postMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error { - r, _, err := _PostMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam) - if r == 0 { - return fmt.Errorf("PostMessage failed: %v", err) - } - return nil -} - -func releaseCapture() bool { - r, _, _ := _ReleaseCapture.Call() - return r != 0 -} - -func registerClassEx(cls *wndClassEx) (uint16, error) { - a, _, err := _RegisterClassExW.Call(uintptr(unsafe.Pointer(cls))) - issue34474KeepAlive(cls) - if a == 0 { - return 0, fmt.Errorf("RegisterClassExW failed: %v", err) - } - return uint16(a), nil -} - -func releaseDC(hdc syscall.Handle) { - _ReleaseDC.Call(uintptr(hdc)) -} - -func setForegroundWindow(hwnd syscall.Handle) { - _SetForegroundWindow.Call(uintptr(hwnd)) -} - -func setFocus(hwnd syscall.Handle) { - _SetFocus.Call(uintptr(hwnd)) -} - -func setProcessDPIAware() { - _SetProcessDPIAware.Call() -} - -func setCapture(hwnd syscall.Handle) syscall.Handle { - r, _, _ := _SetCapture.Call(uintptr(hwnd)) - return syscall.Handle(r) -} - -func setTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error { - r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc) - if r == 0 { - return fmt.Errorf("SetTimer failed: %v", err) - } - return nil -} - -func screenToClient(hwnd syscall.Handle, p *point) { - _ScreenToClient.Call(uintptr(hwnd), uintptr(unsafe.Pointer(p))) - issue34474KeepAlive(p) -} - -func showWindow(hwnd syscall.Handle, nCmdShow int32) { - _ShowWindow.Call(uintptr(hwnd), uintptr(nCmdShow)) -} - -func translateMessage(m *msg) { - _TranslateMessage.Call(uintptr(unsafe.Pointer(m))) - issue34474KeepAlive(m) -} - -func unregisterClass(cls uint16, hInst syscall.Handle) { - _UnregisterClass.Call(uintptr(cls), uintptr(hInst)) -} - -func updateWindow(hwnd syscall.Handle) { - _UpdateWindow.Call(uintptr(hwnd)) -} - -// issue34474KeepAlive calls runtime.KeepAlive as a -// workaround for golang.org/issue/34474. -func issue34474KeepAlive(v interface{}) { - runtime.KeepAlive(v) -} diff --git a/app/internal/windows/windows.go b/app/internal/windows/windows.go new file mode 100644 index 00000000..4fb87dce --- /dev/null +++ b/app/internal/windows/windows.go @@ -0,0 +1,450 @@ +// SPDX-License-Identifier: Unlicense OR MIT + +// +build windows + +package windows + +import ( + "fmt" + "runtime" + "time" + "unsafe" + + syscall "golang.org/x/sys/windows" +) + +type Rect struct { + Left, Top, Right, Bottom int32 +} + +type WndClassEx struct { + CbSize uint32 + Style uint32 + LpfnWndProc uintptr + CnClsExtra int32 + CbWndExtra int32 + HInstance syscall.Handle + HIcon syscall.Handle + HCursor syscall.Handle + HbrBackground syscall.Handle + LpszMenuName *uint16 + LpszClassName *uint16 + HIconSm syscall.Handle +} + +type Msg struct { + Hwnd syscall.Handle + Message uint32 + WParam uintptr + LParam uintptr + Time uint32 + Pt Point + LPrivate uint32 +} + +type Point struct { + X, Y int32 +} + +const ( + CS_HREDRAW = 0x0002 + CS_VREDRAW = 0x0001 + CS_OWNDC = 0x0020 + + CW_USEDEFAULT = -2147483648 + + IDC_ARROW = 32512 + + INFINITE = 0xFFFFFFFF + + LOGPIXELSX = 88 + + MDT_EFFECTIVE_DPI = 0 + + MONITOR_DEFAULTTOPRIMARY = 1 + + SIZE_MAXIMIZED = 2 + SIZE_MINIMIZED = 1 + SIZE_RESTORED = 0 + + SW_SHOWDEFAULT = 10 + + USER_TIMER_MINIMUM = 0x0000000A + + VK_CONTROL = 0x11 + VK_LWIN = 0x5B + VK_MENU = 0x12 + VK_RWIN = 0x5C + VK_SHIFT = 0x10 + + VK_BACK = 0x08 + VK_DELETE = 0x2e + VK_DOWN = 0x28 + VK_END = 0x23 + VK_ESCAPE = 0x1b + VK_HOME = 0x24 + VK_LEFT = 0x25 + VK_NEXT = 0x22 + VK_PRIOR = 0x21 + VK_RIGHT = 0x27 + VK_RETURN = 0x0d + VK_SPACE = 0x20 + VK_TAB = 0x09 + VK_UP = 0x26 + + VK_F1 = 0x70 + VK_F2 = 0x71 + VK_F3 = 0x72 + VK_F4 = 0x73 + VK_F5 = 0x74 + VK_F6 = 0x75 + VK_F7 = 0x76 + VK_F8 = 0x77 + VK_F9 = 0x78 + VK_F10 = 0x79 + VK_F11 = 0x7A + VK_F12 = 0x7B + + VK_OEM_1 = 0xba + VK_OEM_PLUS = 0xbb + VK_OEM_COMMA = 0xbc + VK_OEM_MINUS = 0xbd + VK_OEM_PERIOD = 0xbe + VK_OEM_2 = 0xbf + VK_OEM_3 = 0xc0 + VK_OEM_4 = 0xdb + VK_OEM_5 = 0xdc + VK_OEM_6 = 0xdd + VK_OEM_7 = 0xde + VK_OEM_102 = 0xe2 + + UNICODE_NOCHAR = 65535 + + WM_CANCELMODE = 0x001F + WM_CHAR = 0x0102 + WM_CREATE = 0x0001 + WM_DPICHANGED = 0x02E0 + WM_DESTROY = 0x0002 + WM_ERASEBKGND = 0x0014 + WM_KEYDOWN = 0x0100 + WM_KEYUP = 0x0101 + WM_LBUTTONDOWN = 0x0201 + WM_LBUTTONUP = 0x0202 + WM_MBUTTONDOWN = 0x0207 + WM_MBUTTONUP = 0x0208 + WM_MOUSEMOVE = 0x0200 + WM_MOUSEWHEEL = 0x020A + WM_PAINT = 0x000F + WM_QUIT = 0x0012 + WM_SETFOCUS = 0x0007 + WM_KILLFOCUS = 0x0008 + WM_SHOWWINDOW = 0x0018 + WM_SIZE = 0x0005 + WM_SYSKEYDOWN = 0x0104 + WM_RBUTTONDOWN = 0x0204 + WM_RBUTTONUP = 0x0205 + WM_TIMER = 0x0113 + WM_UNICHAR = 0x0109 + WM_USER = 0x0400 + + WS_CLIPCHILDREN = 0x00010000 + WS_CLIPSIBLINGS = 0x04000000 + WS_VISIBLE = 0x10000000 + WS_OVERLAPPED = 0x00000000 + WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | + WS_MINIMIZEBOX | WS_MAXIMIZEBOX + WS_CAPTION = 0x00C00000 + WS_SYSMENU = 0x00080000 + WS_THICKFRAME = 0x00040000 + WS_MINIMIZEBOX = 0x00020000 + WS_MAXIMIZEBOX = 0x00010000 + + WS_EX_APPWINDOW = 0x00040000 + WS_EX_WINDOWEDGE = 0x00000100 + + QS_ALLINPUT = 0x04FF + + MWMO_WAITALL = 0x0001 + MWMO_INPUTAVAILABLE = 0x0004 + + WAIT_OBJECT_0 = 0 + + PM_REMOVE = 0x0001 + PM_NOREMOVE = 0x0000 +) + +var ( + kernel32 = syscall.NewLazySystemDLL("kernel32.dll") + _GetModuleHandleW = kernel32.NewProc("GetModuleHandleW") + + user32 = syscall.NewLazySystemDLL("user32.dll") + _AdjustWindowRectEx = user32.NewProc("AdjustWindowRectEx") + _CallMsgFilter = user32.NewProc("CallMsgFilterW") + _CreateWindowEx = user32.NewProc("CreateWindowExW") + _DefWindowProc = user32.NewProc("DefWindowProcW") + _DestroyWindow = user32.NewProc("DestroyWindow") + _DispatchMessage = user32.NewProc("DispatchMessageW") + _GetClientRect = user32.NewProc("GetClientRect") + _GetDC = user32.NewProc("GetDC") + _GetKeyState = user32.NewProc("GetKeyState") + _GetMessage = user32.NewProc("GetMessageW") + _GetMessageTime = user32.NewProc("GetMessageTime") + _KillTimer = user32.NewProc("KillTimer") + _LoadCursor = user32.NewProc("LoadCursorW") + _MonitorFromPoint = user32.NewProc("MonitorFromPoint") + _MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx") + _PeekMessage = user32.NewProc("PeekMessageW") + _PostMessage = user32.NewProc("PostMessageW") + _PostQuitMessage = user32.NewProc("PostQuitMessage") + _ReleaseCapture = user32.NewProc("ReleaseCapture") + _RegisterClassExW = user32.NewProc("RegisterClassExW") + _ReleaseDC = user32.NewProc("ReleaseDC") + _ScreenToClient = user32.NewProc("ScreenToClient") + _ShowWindow = user32.NewProc("ShowWindow") + _SetCapture = user32.NewProc("SetCapture") + _SetForegroundWindow = user32.NewProc("SetForegroundWindow") + _SetFocus = user32.NewProc("SetFocus") + _SetProcessDPIAware = user32.NewProc("SetProcessDPIAware") + _SetTimer = user32.NewProc("SetTimer") + _TranslateMessage = user32.NewProc("TranslateMessage") + _UnregisterClass = user32.NewProc("UnregisterClassW") + _UpdateWindow = user32.NewProc("UpdateWindow") + + shcore = syscall.NewLazySystemDLL("shcore") + _GetDpiForMonitor = shcore.NewProc("GetDpiForMonitor") + + gdi32 = syscall.NewLazySystemDLL("gdi32") + _GetDeviceCaps = gdi32.NewProc("GetDeviceCaps") +) + +func GetModuleHandle() (syscall.Handle, error) { + h, _, err := _GetModuleHandleW.Call(uintptr(0)) + if h == 0 { + return 0, fmt.Errorf("GetModuleHandleW failed: %v", err) + } + return syscall.Handle(h), nil +} + +func AdjustWindowRectEx(r *Rect, dwStyle uint32, bMenu int, dwExStyle uint32) { + _AdjustWindowRectEx.Call(uintptr(unsafe.Pointer(r)), uintptr(dwStyle), uintptr(bMenu), uintptr(dwExStyle)) + issue34474KeepAlive(r) +} + +func CallMsgFilter(m *Msg, nCode uintptr) bool { + r, _, _ := _CallMsgFilter.Call(uintptr(unsafe.Pointer(m)), nCode) + issue34474KeepAlive(m) + return r != 0 +} + +func CreateWindowEx(dwExStyle uint32, lpClassName uint16, lpWindowName string, dwStyle uint32, x, y, w, h int32, hWndParent, hMenu, hInstance syscall.Handle, lpParam uintptr) (syscall.Handle, error) { + wname := syscall.StringToUTF16Ptr(lpWindowName) + hwnd, _, err := _CreateWindowEx.Call( + uintptr(dwExStyle), + uintptr(lpClassName), + uintptr(unsafe.Pointer(wname)), + uintptr(dwStyle), + uintptr(x), uintptr(y), + uintptr(w), uintptr(h), + uintptr(hWndParent), + uintptr(hMenu), + uintptr(hInstance), + uintptr(lpParam)) + issue34474KeepAlive(wname) + if hwnd == 0 { + return 0, fmt.Errorf("CreateWindowEx failed: %v", err) + } + return syscall.Handle(hwnd), nil +} + +func DefWindowProc(hwnd syscall.Handle, msg uint32, wparam, lparam uintptr) uintptr { + r, _, _ := _DefWindowProc.Call(uintptr(hwnd), uintptr(msg), wparam, lparam) + return r +} + +func DestroyWindow(hwnd syscall.Handle) { + _DestroyWindow.Call(uintptr(hwnd)) +} + +func DispatchMessage(m *Msg) { + _DispatchMessage.Call(uintptr(unsafe.Pointer(m))) + issue34474KeepAlive(m) +} + +func GetClientRect(hwnd syscall.Handle, r *Rect) { + _GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(r))) + issue34474KeepAlive(r) +} + +func GetDC(hwnd syscall.Handle) (syscall.Handle, error) { + hdc, _, err := _GetDC.Call(uintptr(hwnd)) + if hdc == 0 { + return 0, fmt.Errorf("GetDC failed: %v", err) + } + return syscall.Handle(hdc), nil +} + +func getDeviceCaps(hdc syscall.Handle, index int32) int { + c, _, _ := _GetDeviceCaps.Call(uintptr(hdc), uintptr(index)) + return int(c) +} + +func getDpiForMonitor(hmonitor syscall.Handle, dpiType uint32) int { + var dpiX, dpiY uintptr + _GetDpiForMonitor.Call(uintptr(hmonitor), uintptr(dpiType), uintptr(unsafe.Pointer(&dpiX)), uintptr(unsafe.Pointer(&dpiY))) + return int(dpiX) +} + +// GetSystemDPI returns the effective DPI of the system. +func GetSystemDPI() int { + // Check for getDpiForMonitor, introduced in Windows 8.1. + if _GetDpiForMonitor.Find() == nil { + hmon := monitorFromPoint(Point{}, MONITOR_DEFAULTTOPRIMARY) + return getDpiForMonitor(hmon, MDT_EFFECTIVE_DPI) + } else { + // Fall back to the physical device DPI. + screenDC, err := GetDC(0) + if err != nil { + return 96 + } + defer ReleaseDC(screenDC) + return getDeviceCaps(screenDC, LOGPIXELSX) + } +} + +func GetKeyState(nVirtKey int32) int16 { + c, _, _ := _GetKeyState.Call(uintptr(nVirtKey)) + return int16(c) +} + +func GetMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax uint32) int32 { + r, _, _ := _GetMessage.Call(uintptr(unsafe.Pointer(m)), + uintptr(hwnd), + uintptr(wMsgFilterMin), + uintptr(wMsgFilterMax)) + issue34474KeepAlive(m) + return int32(r) +} + +func GetMessageTime() time.Duration { + r, _, _ := _GetMessageTime.Call() + return time.Duration(r) * time.Millisecond +} + +func KillTimer(hwnd syscall.Handle, nIDEvent uintptr) error { + r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), 0, 0) + if r == 0 { + return fmt.Errorf("KillTimer failed: %v", err) + } + return nil +} + +func LoadCursor(curID uint16) (syscall.Handle, error) { + h, _, err := _LoadCursor.Call(0, uintptr(curID)) + if h == 0 { + return 0, fmt.Errorf("LoadCursorW failed: %v", err) + } + return syscall.Handle(h), nil +} + +func monitorFromPoint(pt Point, flags uint32) syscall.Handle { + r, _, _ := _MonitorFromPoint.Call(uintptr(pt.X), uintptr(pt.Y), uintptr(flags)) + return syscall.Handle(r) +} + +func MsgWaitForMultipleObjectsEx(nCount uint32, pHandles uintptr, millis, mask, flags uint32) (uint32, error) { + r, _, err := _MsgWaitForMultipleObjectsEx.Call(uintptr(nCount), pHandles, uintptr(millis), uintptr(mask), uintptr(flags)) + res := uint32(r) + if res == 0xFFFFFFFF { + return 0, fmt.Errorf("MsgWaitForMultipleObjectsEx failed: %v", err) + } + return res, nil +} + +func PeekMessage(m *Msg, hwnd syscall.Handle, wMsgFilterMin, wMsgFilterMax, wRemoveMsg uint32) bool { + r, _, _ := _PeekMessage.Call(uintptr(unsafe.Pointer(m)), uintptr(hwnd), uintptr(wMsgFilterMin), uintptr(wMsgFilterMax), uintptr(wRemoveMsg)) + issue34474KeepAlive(m) + return r != 0 +} + +func PostQuitMessage(exitCode uintptr) { + _PostQuitMessage.Call(exitCode) +} + +func PostMessage(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) error { + r, _, err := _PostMessage.Call(uintptr(hwnd), uintptr(msg), wParam, lParam) + if r == 0 { + return fmt.Errorf("PostMessage failed: %v", err) + } + return nil +} + +func ReleaseCapture() bool { + r, _, _ := _ReleaseCapture.Call() + return r != 0 +} + +func RegisterClassEx(cls *WndClassEx) (uint16, error) { + a, _, err := _RegisterClassExW.Call(uintptr(unsafe.Pointer(cls))) + issue34474KeepAlive(cls) + if a == 0 { + return 0, fmt.Errorf("RegisterClassExW failed: %v", err) + } + return uint16(a), nil +} + +func ReleaseDC(hdc syscall.Handle) { + _ReleaseDC.Call(uintptr(hdc)) +} + +func SetForegroundWindow(hwnd syscall.Handle) { + _SetForegroundWindow.Call(uintptr(hwnd)) +} + +func SetFocus(hwnd syscall.Handle) { + _SetFocus.Call(uintptr(hwnd)) +} + +func SetProcessDPIAware() { + _SetProcessDPIAware.Call() +} + +func SetCapture(hwnd syscall.Handle) syscall.Handle { + r, _, _ := _SetCapture.Call(uintptr(hwnd)) + return syscall.Handle(r) +} + +func SetTimer(hwnd syscall.Handle, nIDEvent uintptr, uElapse uint32, timerProc uintptr) error { + r, _, err := _SetTimer.Call(uintptr(hwnd), uintptr(nIDEvent), uintptr(uElapse), timerProc) + if r == 0 { + return fmt.Errorf("SetTimer failed: %v", err) + } + return nil +} + +func ScreenToClient(hwnd syscall.Handle, p *Point) { + _ScreenToClient.Call(uintptr(hwnd), uintptr(unsafe.Pointer(p))) + issue34474KeepAlive(p) +} + +func ShowWindow(hwnd syscall.Handle, nCmdShow int32) { + _ShowWindow.Call(uintptr(hwnd), uintptr(nCmdShow)) +} + +func TranslateMessage(m *Msg) { + _TranslateMessage.Call(uintptr(unsafe.Pointer(m))) + issue34474KeepAlive(m) +} + +func UnregisterClass(cls uint16, hInst syscall.Handle) { + _UnregisterClass.Call(uintptr(cls), uintptr(hInst)) +} + +func UpdateWindow(hwnd syscall.Handle) { + _UpdateWindow.Call(uintptr(hwnd)) +} + +// issue34474KeepAlive calls runtime.KeepAlive as a +// workaround for golang.org/issue/34474. +func issue34474KeepAlive(v interface{}) { + runtime.KeepAlive(v) +}