shiny/driver/internal/win32: introduce and use ResizeClientRect
This CL makes screen.NewWindowOptions.Width and
screen.NewWindowOptions.Height parameters of screen.NewWindow
set window's client area of the specified window, instead of
setting dimensions of the bounding rectangle.
Fixes golang/go#19704.
Change-Id: Ic8a819e8127b89cc2734ed26dff6be06d2446ab1
Reviewed-on: https://go-review.googlesource.com/39111
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/shiny/driver/internal/win32/syscall_windows.go b/shiny/driver/internal/win32/syscall_windows.go
index 53857c4..36e0dfe 100644
--- a/shiny/driver/internal/win32/syscall_windows.go
+++ b/shiny/driver/internal/win32/syscall_windows.go
@@ -168,12 +168,14 @@
//sys _DestroyWindow(hwnd syscall.Handle) (err error) = user32.DestroyWindow
//sys _DispatchMessage(msg *_MSG) (ret int32) = user32.DispatchMessageW
//sys _GetClientRect(hwnd syscall.Handle, rect *_RECT) (err error) = user32.GetClientRect
+//sys _GetWindowRect(hwnd syscall.Handle, rect *_RECT) (err error) = user32.GetWindowRect
//sys _GetKeyboardLayout(threadID uint32) (locale syscall.Handle) = user32.GetKeyboardLayout
//sys _GetKeyboardState(lpKeyState *byte) (err error) = user32.GetKeyboardState
//sys _GetKeyState(virtkey int32) (keystatus int16) = user32.GetKeyState
//sys _GetMessage(msg *_MSG, hwnd syscall.Handle, msgfiltermin uint32, msgfiltermax uint32) (ret int32, err error) [failretval==-1] = user32.GetMessageW
//sys _LoadCursor(hInstance syscall.Handle, cursorName uintptr) (cursor syscall.Handle, err error) = user32.LoadCursorW
//sys _LoadIcon(hInstance syscall.Handle, iconName uintptr) (icon syscall.Handle, err error) = user32.LoadIconW
+//sys _MoveWindow(hwnd syscall.Handle, x int32, y int32, w int32, h int32, repaint bool) (err error) = user32.MoveWindow
//sys _PostMessage(hwnd syscall.Handle, uMsg uint32, wParam uintptr, lParam uintptr) (lResult bool) = user32.PostMessageW
//sys _PostQuitMessage(exitCode int32) = user32.PostQuitMessage
//sys _RegisterClass(wc *_WNDCLASS) (atom uint16, err error) = user32.RegisterClassW
diff --git a/shiny/driver/internal/win32/win32.go b/shiny/driver/internal/win32/win32.go
index 402b575..5836073 100644
--- a/shiny/driver/internal/win32/win32.go
+++ b/shiny/driver/internal/win32/win32.go
@@ -70,20 +70,11 @@
if err != nil {
return 0, err
}
- w, h := _CW_USEDEFAULT, _CW_USEDEFAULT
- if opts != nil {
- if opts.Width > 0 {
- w = opts.Width
- }
- if opts.Height > 0 {
- h = opts.Height
- }
- }
hwnd, err := _CreateWindowEx(0,
wcname, title,
_WS_OVERLAPPEDWINDOW,
_CW_USEDEFAULT, _CW_USEDEFAULT,
- int32(w), int32(h),
+ _CW_USEDEFAULT, _CW_USEDEFAULT,
0, 0, hThisInstance, 0)
if err != nil {
return 0, err
@@ -94,6 +85,25 @@
return hwnd, nil
}
+// ResizeClientRect makes hwnd client rectangle opts.Width by opts.Height in size.
+func ResizeClientRect(hwnd syscall.Handle, opts *screen.NewWindowOptions) error {
+ if opts == nil || opts.Width <= 0 || opts.Height <= 0 {
+ return nil
+ }
+ var cr, wr _RECT
+ err := _GetClientRect(hwnd, &cr)
+ if err != nil {
+ return err
+ }
+ err = _GetWindowRect(hwnd, &wr)
+ if err != nil {
+ return err
+ }
+ w := (wr.Right - wr.Left) - (cr.Right - int32(opts.Width))
+ h := (wr.Bottom - wr.Top) - (cr.Bottom - int32(opts.Height))
+ return _MoveWindow(hwnd, wr.Left, wr.Top, w, h, false)
+}
+
// Show shows a newly created window.
// It sends the appropriate lifecycle events, makes the window appear
// on the screen, and sends an initial size event.
diff --git a/shiny/driver/internal/win32/zsyscall_windows.go b/shiny/driver/internal/win32/zsyscall_windows.go
index 07430ac..1759c01 100644
--- a/shiny/driver/internal/win32/zsyscall_windows.go
+++ b/shiny/driver/internal/win32/zsyscall_windows.go
@@ -47,12 +47,14 @@
procDestroyWindow = moduser32.NewProc("DestroyWindow")
procDispatchMessageW = moduser32.NewProc("DispatchMessageW")
procGetClientRect = moduser32.NewProc("GetClientRect")
+ procGetWindowRect = moduser32.NewProc("GetWindowRect")
procGetKeyboardLayout = moduser32.NewProc("GetKeyboardLayout")
procGetKeyboardState = moduser32.NewProc("GetKeyboardState")
procGetKeyState = moduser32.NewProc("GetKeyState")
procGetMessageW = moduser32.NewProc("GetMessageW")
procLoadCursorW = moduser32.NewProc("LoadCursorW")
procLoadIconW = moduser32.NewProc("LoadIconW")
+ procMoveWindow = moduser32.NewProc("MoveWindow")
procPostMessageW = moduser32.NewProc("PostMessageW")
procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
procRegisterClassW = moduser32.NewProc("RegisterClassW")
@@ -142,6 +144,18 @@
return
}
+func _GetWindowRect(hwnd syscall.Handle, rect *_RECT) (err error) {
+ r1, _, e1 := syscall.Syscall(procGetWindowRect.Addr(), 2, uintptr(hwnd), uintptr(unsafe.Pointer(rect)), 0)
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
func _GetKeyboardLayout(threadID uint32) (locale syscall.Handle) {
r0, _, _ := syscall.Syscall(procGetKeyboardLayout.Addr(), 1, uintptr(threadID), 0, 0)
locale = syscall.Handle(r0)
@@ -205,6 +219,24 @@
return
}
+func _MoveWindow(hwnd syscall.Handle, x int32, y int32, w int32, h int32, repaint bool) (err error) {
+ var _p0 uint32
+ if repaint {
+ _p0 = 1
+ } else {
+ _p0 = 0
+ }
+ r1, _, e1 := syscall.Syscall6(procMoveWindow.Addr(), 6, uintptr(hwnd), uintptr(x), uintptr(y), uintptr(w), uintptr(h), uintptr(_p0))
+ if r1 == 0 {
+ if e1 != 0 {
+ err = errnoErr(e1)
+ } else {
+ err = syscall.EINVAL
+ }
+ }
+ return
+}
+
func _PostMessage(hwnd syscall.Handle, uMsg uint32, wParam uintptr, lParam uintptr) (lResult bool) {
r0, _, _ := syscall.Syscall6(procPostMessageW.Addr(), 4, uintptr(hwnd), uintptr(uMsg), uintptr(wParam), uintptr(lParam), 0, 0)
lResult = r0 != 0
diff --git a/shiny/driver/windriver/screen.go b/shiny/driver/windriver/screen.go
index 98f35f9..3e84345 100644
--- a/shiny/driver/windriver/screen.go
+++ b/shiny/driver/windriver/screen.go
@@ -74,6 +74,11 @@
s.windows[w.hwnd] = w
s.mu.Unlock()
+ err = win32.ResizeClientRect(w.hwnd, opts)
+ if err != nil {
+ return nil, err
+ }
+
win32.Show(w.hwnd)
return w, nil
}