app: [Windows] support resize gestures for undecorated windows

We're about to remove the client-controlled system.Action machinery
for resize gestures initiated by the client. This is the replacement
implementation for Windows, where the behaviour is hard-coded to
mimic the decorated automatic handling.

Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
Elias Naur
2022-06-25 14:05:03 +01:00
parent 45443a2c3a
commit fd3a3eb1b9
2 changed files with 68 additions and 4 deletions
+20 -2
View File
@@ -113,7 +113,15 @@ const (
HWND_TOPMOST = ^(uint32(1) - 1) // -1
HTCLIENT = 1
HTCLIENT = 1
HTLEFT = 10
HTRIGHT = 11
HTTOP = 12
HTTOPLEFT = 13
HTTOPRIGHT = 14
HTBOTTOM = 15
HTBOTTOMLEFT = 16
HTBOTTOMRIGHT = 17
IDC_APPSTARTING = 32650 // Standard arrow and small hourglass
IDC_ARROW = 32512 // Standard arrow
@@ -146,13 +154,16 @@ const (
SCS_SETSTR = GCS_COMPREADSTR | GCS_COMPSTR
SM_CXSIZEFRAME = 32
SM_CYSIZEFRAME = 33
SW_SHOWDEFAULT = 10
SW_SHOWMINIMIZED = 2
SW_SHOWMAXIMIZED = 3
SW_SHOWNORMAL = 1
SW_SHOW = 5
SWP_FRAMECHANGED = 0x0020
SWP_FRAMECHANGED = 0x0020
SWP_NOMOVE = 0x0002
SWP_NOOWNERZORDER = 0x0200
SWP_NOSIZE = 0x0001
@@ -231,6 +242,7 @@ const (
WM_MOUSEMOVE = 0x0200
WM_MOUSEWHEEL = 0x020A
WM_MOUSEHWHEEL = 0x020E
WM_NCHITTEST = 0x0084
WM_PAINT = 0x000F
WM_QUIT = 0x0012
WM_SETCURSOR = 0x0020
@@ -316,6 +328,7 @@ var (
_GetMessage = user32.NewProc("GetMessageW")
_GetMessageTime = user32.NewProc("GetMessageTime")
_GetMonitorInfo = user32.NewProc("GetMonitorInfoW")
_GetSystemMetrics = user32.NewProc("GetSystemMetrics")
_GetWindowLong = user32.NewProc("GetWindowLongPtrW")
_GetWindowLong32 = user32.NewProc("GetWindowLongW")
_GetWindowPlacement = user32.NewProc("GetWindowPlacement")
@@ -499,6 +512,11 @@ func GetMessageTime() time.Duration {
return time.Duration(r) * time.Millisecond
}
func GetSystemMetrics(nIndex int) int {
r, _, _ := _GetSystemMetrics.Call(uintptr(nIndex))
return int(r)
}
// GetWindowDPI returns the effective DPI of the window.
func GetWindowDPI(hwnd syscall.Handle) int {
// Check for GetDpiForWindow, introduced in Windows 10.
+48 -2
View File
@@ -54,8 +54,9 @@ type window struct {
animating bool
deltas winDeltas
config Config
deltas winDeltas
borderSize image.Point
config Config
}
const _WM_WAKEUP = windows.WM_USER + iota
@@ -210,6 +211,11 @@ func (w *window) update() {
}
}
w.config.Size = size
w.borderSize = image.Pt(
windows.GetSystemMetrics(windows.SM_CXSIZEFRAME),
windows.GetSystemMetrics(windows.SM_CYSIZEFRAME),
)
w.w.Event(ConfigEvent{Config: w.config})
}
@@ -279,6 +285,15 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
w.w.Event(key.FocusEvent{Focus: true})
case windows.WM_KILLFOCUS:
w.w.Event(key.FocusEvent{Focus: false})
case windows.WM_NCHITTEST:
if w.config.Decorated || w.config.Mode != Windowed {
// Let the system handle it.
break
}
x, y := coordsFromlParam(lParam)
np := windows.Point{X: int32(x), Y: int32(y)}
windows.ScreenToClient(w.hwnd, &np)
return w.hitTest(int(np.X), int(np.Y))
case windows.WM_MOUSEMOVE:
x, y := coordsFromlParam(lParam)
p := f32.Point{X: float32(x), Y: float32(y)}
@@ -411,6 +426,37 @@ func getModifiers() key.Modifiers {
return kmods
}
// hitTest returns the non-client area hit by the point, needed to
// process WM_NCHITTEST.
func (w *window) hitTest(x, y int) uintptr {
top := y <= w.borderSize.Y
bottom := y >= w.config.Size.Y-w.borderSize.Y
left := x <= w.borderSize.X
right := x >= w.config.Size.X-w.borderSize.X
switch {
default:
fallthrough
case !top && !bottom && !left && !right:
return windows.HTCLIENT
case top && left:
return windows.HTTOPLEFT
case top && right:
return windows.HTTOPRIGHT
case bottom && left:
return windows.HTBOTTOMLEFT
case bottom && right:
return windows.HTBOTTOMRIGHT
case top:
return windows.HTTOP
case bottom:
return windows.HTBOTTOM
case left:
return windows.HTLEFT
case right:
return windows.HTRIGHT
}
}
func (w *window) pointerButton(btn pointer.Buttons, press bool, lParam uintptr, kmods key.Modifiers) {
var typ pointer.Type
if press {