~eliasnaur/gio#631: 
[Windows] Impossible to create reliable fixed size window

Creating a window with options app.MinSize and app.MaxSize set to the same values will make the window behave oddly. The maximize button is still clickable and when clicked, the window randomly moves to the left-top corner of the screen while retaining the same size and its maximized state (the maximize icon will update to its counterpart icon until clicked again or the window is manually moved). Additionally, when hovering over the window's frame, the cursor displays the resize icon which, as far as I've tested, doesn't happen if a win32 window is properly set up to not allow resizing.

So my suggestion is to either make it so when app.MinSize and app.MaxSize are set to the same values, correctly mark the window as unresizable and unmaximizable; Or, add a new option to achieve this goal.

Below example code reproduces the issue:

package main

import (
	"log"
	"os"

	"gioui.org/app"
	"gioui.org/op"
	"gioui.org/widget/material"
)

func main() {
	go func() {
		window := new(app.Window)
		window.Option(
			app.MinSize(800, 600),
			app.MaxSize(800, 600),
		)
		err := run(window)
		if err != nil {
			log.Fatal(err)
		}
		os.Exit(0)
	}()
	app.Main()
}

func run(window *app.Window) error {
	theme := material.NewTheme()
	var ops op.Ops
	for {
		switch e := window.Event().(type) {
		case app.DestroyEvent:
			return e.Err
		case app.FrameEvent:
			gtx := app.NewContext(&ops, e)

			title := material.H1(theme, "Test 123")
			title.Layout(gtx)

			e.Frame(gtx.Ops)
		}
	}
}
Status
RESOLVED FIXED
Submitter
~vasijob225
Assigned to
No-one
Submitted
a month ago
Updated
a month ago
Labels
No labels applied.

~vasijob225 a month ago · edit

I managed to find a temporary workaround to achieve the effect I want by modifying the HWND on a Win32ViewEvent. I feel like this is quite a hack though as it's modifying the window AFTER it's created and not intercepting the window creation itself, so it would still be much better to have that sorted out in the library. Here is the code in case it's of any help:

package main

import (
	"log"
	"os"

	"gioui.org/app"
	"gioui.org/op"
	"gioui.org/widget/material"
	"golang.org/x/sys/windows"
)

const (
	GWL_STYLE        = -16
	WS_BORDER        = 0x00800000
	WS_CAPTION       = 0x00C00000
	WS_SYSMENU       = 0x00080000
	WS_MINIMIZEBOX   = 0x00020000
	WS_VISIBLE       = 0x10000000
	SWP_NOSIZE       = 0x0001
	SWP_NOMOVE       = 0x0002
	SWP_FRAMECHANGED = 0x0020
)

var (
	user32               = windows.NewLazySystemDLL("user32.dll")
	procSetWindowLongPtr = user32.NewProc("SetWindowLongPtrW")
	procSetWindowPos     = user32.NewProc("SetWindowPos")
)

func setWindowLongPtr(hWnd uintptr, index int, newLong uintptr) {
	procSetWindowLongPtr.Call(hWnd, uintptr(index), newLong)
}

func setWindowPos(hWnd uintptr) {
	procSetWindowPos.Call(hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED)
}

func main() {
	go func() {
		window := new(app.Window)
		window.Option(
			app.MinSize(400, 300),
			app.MaxSize(400, 300),
		)
		err := run(window)
		if err != nil {
			log.Fatal(err)
		}
		os.Exit(0)
	}()
	app.Main()
}

func run(window *app.Window) error {
	theme := material.NewTheme()
	var ops op.Ops
	for {
		switch e := window.Event().(type) {
		case app.DestroyEvent:
			return e.Err
		case app.Win32ViewEvent:
			log.Println(e.HWND)

			window.Run(func() {
				setWindowLongPtr(e.HWND, GWL_STYLE, WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_VISIBLE)
				setWindowPos(e.HWND)
			})
		case app.FrameEvent:
			gtx := app.NewContext(&ops, e)

			title := material.H1(theme, "Test 123")
			title.Layout(gtx)

			e.Frame(gtx.Ops)
		}
	}
}

~eliasnaur a month ago

Related: https://github.com/gioui/gio/pull/143

It seems to me the maximize button should be hidden whenever MaxSize != {0,0}. Further, if MinSize == MaxSize the frame resizing should be disabled, as you suggest.

Would you like to attempt a patch? window.Configure is probably the right place to edit. It's ok if the change only works for Windows.

~vasijob225 a month ago · edit

I agree, I'm going to try to submit a patch.

~vasijob225 a month ago* · edit

I submitted a patch here: https://lists.sr.ht/~eliasnaur/gio-patches/patches/57210

I'm not very experienced with git so I'm not sure if I did it right though.. Please let me know if there's anything wrong with it.

~eliasnaur REPORTED FIXED a month ago

vasijob225 referenced this ticket in commit 95354d8.

Register here or Log in to comment, or comment via email.