mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-05 01:15:35 +00:00
app: [Windows] remove padding from maximized custom decorated windows
As described in https://devblogs.microsoft.com/oldnewthing/20150304-00/?p=44543 Windows extends maximized windows outside the visible display. This is not appropriate for custom decorated windows, so this change implements a workaround in the handling of WM_NCCALCSIZE. While here, replace the deltas field from window state to fix issues when switching between decoration modes. Signed-off-by: Elias Naur <mail@eliasnaur.com>
This commit is contained in:
@@ -76,6 +76,21 @@ type MinMaxInfo struct {
|
|||||||
PtMaxTrackSize Point
|
PtMaxTrackSize Point
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NCCalcSizeParams struct {
|
||||||
|
Rgrc [3]Rect
|
||||||
|
LpPos *WindowPos
|
||||||
|
}
|
||||||
|
|
||||||
|
type WindowPos struct {
|
||||||
|
HWND syscall.Handle
|
||||||
|
HWNDInsertAfter syscall.Handle
|
||||||
|
x int32
|
||||||
|
y int32
|
||||||
|
cx int32
|
||||||
|
cy int32
|
||||||
|
flags uint32
|
||||||
|
}
|
||||||
|
|
||||||
type WindowPlacement struct {
|
type WindowPlacement struct {
|
||||||
length uint32
|
length uint32
|
||||||
flags uint32
|
flags uint32
|
||||||
@@ -331,6 +346,7 @@ var (
|
|||||||
_DispatchMessage = user32.NewProc("DispatchMessageW")
|
_DispatchMessage = user32.NewProc("DispatchMessageW")
|
||||||
_EmptyClipboard = user32.NewProc("EmptyClipboard")
|
_EmptyClipboard = user32.NewProc("EmptyClipboard")
|
||||||
_GetWindowRect = user32.NewProc("GetWindowRect")
|
_GetWindowRect = user32.NewProc("GetWindowRect")
|
||||||
|
_GetClientRect = user32.NewProc("GetClientRect")
|
||||||
_GetClipboardData = user32.NewProc("GetClipboardData")
|
_GetClipboardData = user32.NewProc("GetClipboardData")
|
||||||
_GetDC = user32.NewProc("GetDC")
|
_GetDC = user32.NewProc("GetDC")
|
||||||
_GetDpiForWindow = user32.NewProc("GetDpiForWindow")
|
_GetDpiForWindow = user32.NewProc("GetDpiForWindow")
|
||||||
@@ -463,6 +479,12 @@ func GetWindowRect(hwnd syscall.Handle) Rect {
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetClientRect(hwnd syscall.Handle) Rect {
|
||||||
|
var r Rect
|
||||||
|
_GetClientRect.Call(uintptr(hwnd), uintptr(unsafe.Pointer(&r)))
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func GetClipboardData(format uint32) (syscall.Handle, error) {
|
func GetClipboardData(format uint32) (syscall.Handle, error) {
|
||||||
r, _, err := _GetClipboardData.Call(uintptr(format))
|
r, _, err := _GetClipboardData.Call(uintptr(format))
|
||||||
if r == 0 {
|
if r == 0 {
|
||||||
|
|||||||
+47
-42
@@ -32,11 +32,6 @@ type ViewEvent struct {
|
|||||||
HWND uintptr
|
HWND uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
type winDeltas struct {
|
|
||||||
width int32
|
|
||||||
height int32
|
|
||||||
}
|
|
||||||
|
|
||||||
type window struct {
|
type window struct {
|
||||||
hwnd syscall.Handle
|
hwnd syscall.Handle
|
||||||
hdc syscall.Handle
|
hdc syscall.Handle
|
||||||
@@ -55,7 +50,6 @@ type window struct {
|
|||||||
animating bool
|
animating bool
|
||||||
focused bool
|
focused bool
|
||||||
|
|
||||||
deltas winDeltas
|
|
||||||
borderSize image.Point
|
borderSize image.Point
|
||||||
config Config
|
config Config
|
||||||
}
|
}
|
||||||
@@ -192,22 +186,12 @@ func createNativeWindow() (*window, error) {
|
|||||||
// It reads the window style and size/position and updates w.config.
|
// It reads the window style and size/position and updates w.config.
|
||||||
// If anything has changed it emits a ConfigEvent to notify the application.
|
// If anything has changed it emits a ConfigEvent to notify the application.
|
||||||
func (w *window) update() {
|
func (w *window) update() {
|
||||||
r := windows.GetWindowRect(w.hwnd)
|
cr := windows.GetClientRect(w.hwnd)
|
||||||
size := image.Point{
|
w.config.Size = image.Point{
|
||||||
X: int(r.Right - r.Left - w.deltas.width),
|
X: int(cr.Right - cr.Left),
|
||||||
Y: int(r.Bottom - r.Top - w.deltas.height),
|
Y: int(cr.Bottom - cr.Top),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the window mode.
|
|
||||||
style := windows.GetWindowLong(w.hwnd, windows.GWL_STYLE)
|
|
||||||
if style&windows.WS_OVERLAPPEDWINDOW == 0 {
|
|
||||||
size = image.Point{
|
|
||||||
X: int(r.Right - r.Left),
|
|
||||||
Y: int(r.Bottom - r.Top),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.config.Size = size
|
|
||||||
|
|
||||||
w.borderSize = image.Pt(
|
w.borderSize = image.Pt(
|
||||||
windows.GetSystemMetrics(windows.SM_CXSIZEFRAME),
|
windows.GetSystemMetrics(windows.SM_CXSIZEFRAME),
|
||||||
windows.GetSystemMetrics(windows.SM_CYSIZEFRAME),
|
windows.GetSystemMetrics(windows.SM_CYSIZEFRAME),
|
||||||
@@ -326,10 +310,27 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
|||||||
w.hwnd = 0
|
w.hwnd = 0
|
||||||
windows.PostQuitMessage(0)
|
windows.PostQuitMessage(0)
|
||||||
case windows.WM_NCCALCSIZE:
|
case windows.WM_NCCALCSIZE:
|
||||||
if !w.config.Decorated {
|
if w.config.Decorated {
|
||||||
// No client areas; we draw decorations ourselves.
|
// Let Windows handle decorations.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// No client areas; we draw decorations ourselves.
|
||||||
|
if wParam != 1 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
// lParam contains an NCCALCSIZE_PARAMS for us to adjust.
|
||||||
|
place := windows.GetWindowPlacement(w.hwnd)
|
||||||
|
if !place.IsMaximized() {
|
||||||
|
// Nothing do adjust.
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
// Adjust window position to avoid the extra padding in maximized
|
||||||
|
// state. See https://devblogs.microsoft.com/oldnewthing/20150304-00/?p=44543.
|
||||||
|
// Note that trying to do the adjustment in WM_GETMINMAXINFO is ignored by Windows.
|
||||||
|
szp := (*windows.NCCalcSizeParams)(unsafe.Pointer(uintptr(lParam)))
|
||||||
|
mi := windows.GetMonitorInfo(w.hwnd)
|
||||||
|
szp.Rgrc[0] = mi.WorkArea
|
||||||
|
return 0
|
||||||
case windows.WM_PAINT:
|
case windows.WM_PAINT:
|
||||||
w.draw(true)
|
w.draw(true)
|
||||||
case windows.WM_SIZE:
|
case windows.WM_SIZE:
|
||||||
@@ -349,18 +350,26 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
|||||||
}
|
}
|
||||||
case windows.WM_GETMINMAXINFO:
|
case windows.WM_GETMINMAXINFO:
|
||||||
mm := (*windows.MinMaxInfo)(unsafe.Pointer(uintptr(lParam)))
|
mm := (*windows.MinMaxInfo)(unsafe.Pointer(uintptr(lParam)))
|
||||||
|
var bw, bh int32
|
||||||
|
if w.config.Decorated {
|
||||||
|
r := windows.GetWindowRect(w.hwnd)
|
||||||
|
cr := windows.GetClientRect(w.hwnd)
|
||||||
|
bw = r.Right - r.Left - (cr.Right - cr.Left)
|
||||||
|
bh = r.Bottom - r.Top - (cr.Bottom - cr.Top)
|
||||||
|
}
|
||||||
if p := w.config.MinSize; p.X > 0 || p.Y > 0 {
|
if p := w.config.MinSize; p.X > 0 || p.Y > 0 {
|
||||||
mm.PtMinTrackSize = windows.Point{
|
mm.PtMinTrackSize = windows.Point{
|
||||||
X: int32(p.X) + w.deltas.width,
|
X: int32(p.X) + bw,
|
||||||
Y: int32(p.Y) + w.deltas.height,
|
Y: int32(p.Y) + bh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if p := w.config.MaxSize; p.X > 0 || p.Y > 0 {
|
if p := w.config.MaxSize; p.X > 0 || p.Y > 0 {
|
||||||
mm.PtMaxTrackSize = windows.Point{
|
mm.PtMaxTrackSize = windows.Point{
|
||||||
X: int32(p.X) + w.deltas.width,
|
X: int32(p.X) + bw,
|
||||||
Y: int32(p.Y) + w.deltas.height,
|
Y: int32(p.Y) + bh,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0
|
||||||
case windows.WM_SETCURSOR:
|
case windows.WM_SETCURSOR:
|
||||||
w.cursorIn = (lParam & 0xffff) == windows.HTCLIENT
|
w.cursorIn = (lParam & 0xffff) == windows.HTCLIENT
|
||||||
if w.cursorIn {
|
if w.cursorIn {
|
||||||
@@ -693,23 +702,19 @@ func (w *window) Configure(options []Option) {
|
|||||||
height = int32(w.config.Size.Y)
|
height = int32(w.config.Size.Y)
|
||||||
// Get the current window size and position.
|
// Get the current window size and position.
|
||||||
wr := windows.GetWindowRect(w.hwnd)
|
wr := windows.GetWindowRect(w.hwnd)
|
||||||
// Set desired window size.
|
|
||||||
wr.Right = wr.Left + width
|
|
||||||
wr.Bottom = wr.Top + height
|
|
||||||
// Compute client size and position. Note that the client size is
|
|
||||||
// equal to the window size when we are in control of decorations.
|
|
||||||
r := wr
|
|
||||||
if w.config.Decorated {
|
|
||||||
windows.AdjustWindowRectEx(&r, uint32(style), 0, dwExStyle)
|
|
||||||
}
|
|
||||||
// Calculate difference between client and full window sizes.
|
|
||||||
w.deltas.width = r.Right - wr.Right + wr.Left - r.Left
|
|
||||||
w.deltas.height = r.Bottom - wr.Bottom + wr.Top - r.Top
|
|
||||||
// Set new window size and position.
|
|
||||||
x = wr.Left
|
x = wr.Left
|
||||||
y = wr.Top
|
y = wr.Top
|
||||||
width = r.Right - r.Left
|
if w.config.Decorated {
|
||||||
height = r.Bottom - r.Top
|
// Compute client size and position. Note that the client size is
|
||||||
|
// equal to the window size when we are in control of decorations.
|
||||||
|
r := windows.Rect{
|
||||||
|
Right: width,
|
||||||
|
Bottom: height,
|
||||||
|
}
|
||||||
|
windows.AdjustWindowRectEx(&r, uint32(style), 0, dwExStyle)
|
||||||
|
width = r.Right - r.Left
|
||||||
|
height = r.Bottom - r.Top
|
||||||
|
}
|
||||||
if !w.config.Decorated {
|
if !w.config.Decorated {
|
||||||
// Enable drop shadows when we draw decorations.
|
// Enable drop shadows when we draw decorations.
|
||||||
windows.DwmExtendFrameIntoClientArea(w.hwnd, windows.Margins{-1, -1, -1, -1})
|
windows.DwmExtendFrameIntoClientArea(w.hwnd, windows.Margins{-1, -1, -1, -1})
|
||||||
@@ -726,7 +731,7 @@ func (w *window) Configure(options []Option) {
|
|||||||
windows.SetWindowPos(w.hwnd, 0, x, y, width, height, swpStyle)
|
windows.SetWindowPos(w.hwnd, 0, x, y, width, height, swpStyle)
|
||||||
windows.ShowWindow(w.hwnd, showMode)
|
windows.ShowWindow(w.hwnd, showMode)
|
||||||
|
|
||||||
w.w.Event(ConfigEvent{Config: w.config})
|
w.update()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *window) WriteClipboard(s string) {
|
func (w *window) WriteClipboard(s string) {
|
||||||
|
|||||||
Reference in New Issue
Block a user