mirror of
https://git.sr.ht/~eliasnaur/gio
synced 2026-07-06 09:55:40 +00:00
app/window,app/internal/window: allow min/max window size
The app.MinSize and app.MaxSize options restricts the window size: w := app.NewWindow( app.Size(unit.Dp(600), unit.Dp(596)), app.MinSize(unit.Dp(600), unit.Dp(596)), app.MaxSize(unit.Dp(600), unit.Dp(596)), app.Title(APPNAME), ) Signed-off-by: Jason <sourcehut@sweatyballs.es>
This commit is contained in:
@@ -41,7 +41,7 @@ __attribute__ ((visibility ("hidden"))) CFTypeRef gio_readClipboard(void);
|
|||||||
__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length);
|
__attribute__ ((visibility ("hidden"))) void gio_writeClipboard(unichar *chars, NSUInteger length);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef);
|
__attribute__ ((visibility ("hidden"))) void gio_setNeedsDisplay(CFTypeRef viewRef);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_appTerminate(void);
|
__attribute__ ((visibility ("hidden"))) void gio_appTerminate(void);
|
||||||
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height);
|
__attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef);
|
__attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef);
|
||||||
__attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft);
|
__attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft);
|
||||||
__attribute__ ((visibility ("hidden"))) void gio_close(CFTypeRef windowRef);
|
__attribute__ ((visibility ("hidden"))) void gio_close(CFTypeRef windowRef);
|
||||||
@@ -323,12 +323,21 @@ func NewWindow(win Callbacks, opts *Options) error {
|
|||||||
// Window sizes is in unscaled screen coordinates, not device pixels.
|
// Window sizes is in unscaled screen coordinates, not device pixels.
|
||||||
width = int(float32(width) / screenScale)
|
width = int(float32(width) / screenScale)
|
||||||
height = int(float32(height) / screenScale)
|
height = int(float32(height) / screenScale)
|
||||||
|
minWidth := cfg.Px(opts.MinWidth)
|
||||||
|
minHeight := cfg.Px(opts.MinHeight)
|
||||||
|
minWidth = int(float32(minWidth) / screenScale)
|
||||||
|
minHeight = int(float32(minHeight) / screenScale)
|
||||||
|
maxWidth := cfg.Px(opts.MaxWidth)
|
||||||
|
maxHeight := cfg.Px(opts.MaxHeight)
|
||||||
|
maxWidth = int(float32(maxWidth) / screenScale)
|
||||||
|
maxHeight = int(float32(maxHeight) / screenScale)
|
||||||
title := C.CString(opts.Title)
|
title := C.CString(opts.Title)
|
||||||
defer C.free(unsafe.Pointer(title))
|
defer C.free(unsafe.Pointer(title))
|
||||||
errch <- nil
|
errch <- nil
|
||||||
win.SetDriver(w)
|
win.SetDriver(w)
|
||||||
w.w = win
|
w.w = win
|
||||||
w.window = C.gio_createWindow(w.view, title, C.CGFloat(width), C.CGFloat(height))
|
w.window = C.gio_createWindow(w.view, title, C.CGFloat(width), C.CGFloat(height),
|
||||||
|
C.CGFloat(minWidth), C.CGFloat(minHeight), C.CGFloat(maxWidth), C.CGFloat(maxHeight))
|
||||||
if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
|
if nextTopLeft.x == 0 && nextTopLeft.y == 0 {
|
||||||
// cascadeTopLeftFromPoint treats (0, 0) as a no-op,
|
// cascadeTopLeftFromPoint treats (0, 0) as a no-op,
|
||||||
// and just returns the offset we need for the first window.
|
// and just returns the offset we need for the first window.
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ void gio_makeKeyAndOrderFront(CFTypeRef windowRef) {
|
|||||||
[window makeKeyAndOrderFront:nil];
|
[window makeKeyAndOrderFront:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height) {
|
CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, CGFloat height, CGFloat minWidth, CGFloat minHeight, CGFloat maxWidth, CGFloat maxHeight) {
|
||||||
@autoreleasepool {
|
@autoreleasepool {
|
||||||
NSRect rect = NSMakeRect(0, 0, width, height);
|
NSRect rect = NSMakeRect(0, 0, width, height);
|
||||||
NSUInteger styleMask = NSTitledWindowMask |
|
NSUInteger styleMask = NSTitledWindowMask |
|
||||||
@@ -136,6 +136,12 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width,
|
|||||||
styleMask:styleMask
|
styleMask:styleMask
|
||||||
backing:NSBackingStoreBuffered
|
backing:NSBackingStoreBuffered
|
||||||
defer:NO];
|
defer:NO];
|
||||||
|
if (minWidth > 0 || minHeight > 0) {
|
||||||
|
window.contentMinSize = NSMakeSize(minWidth, minHeight);
|
||||||
|
}
|
||||||
|
if (maxWidth > 0 || maxHeight > 0) {
|
||||||
|
window.contentMaxSize = NSMakeSize(maxWidth, maxHeight);
|
||||||
|
}
|
||||||
[window setAcceptsMouseMovedEvents:YES];
|
[window setAcceptsMouseMovedEvents:YES];
|
||||||
window.title = [NSString stringWithUTF8String: title];
|
window.title = [NSString stringWithUTF8String: title];
|
||||||
NSView *view = (__bridge NSView *)viewRef;
|
NSView *view = (__bridge NSView *)viewRef;
|
||||||
|
|||||||
@@ -27,6 +27,16 @@ import (
|
|||||||
"gioui.org/io/system"
|
"gioui.org/io/system"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type winConstraints struct {
|
||||||
|
minWidth, minHeight int32
|
||||||
|
maxWidth, maxHeight int32
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
@@ -39,6 +49,10 @@ type window struct {
|
|||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
animating bool
|
animating bool
|
||||||
|
|
||||||
|
minmax winConstraints
|
||||||
|
deltas winDeltas
|
||||||
|
opts *Options
|
||||||
}
|
}
|
||||||
|
|
||||||
const _WM_REDRAW = windows.WM_USER + 0
|
const _WM_REDRAW = windows.WM_USER + 0
|
||||||
@@ -137,6 +151,15 @@ func initResources() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getWindowConstraints(cfg unit.Metric, opts *Options, d winDeltas) winConstraints {
|
||||||
|
var minmax winConstraints
|
||||||
|
minmax.minWidth = int32(cfg.Px(opts.MinWidth)) + d.width
|
||||||
|
minmax.minHeight = int32(cfg.Px(opts.MinHeight)) + d.height
|
||||||
|
minmax.maxWidth = int32(cfg.Px(opts.MaxWidth)) + d.width
|
||||||
|
minmax.maxHeight = int32(cfg.Px(opts.MaxHeight)) + d.height
|
||||||
|
return minmax
|
||||||
|
}
|
||||||
|
|
||||||
func createNativeWindow(opts *Options) (*window, error) {
|
func createNativeWindow(opts *Options) (*window, error) {
|
||||||
var resErr error
|
var resErr error
|
||||||
resources.once.Do(func() {
|
resources.once.Do(func() {
|
||||||
@@ -152,7 +175,14 @@ func createNativeWindow(opts *Options) (*window, error) {
|
|||||||
}
|
}
|
||||||
dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW)
|
dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW)
|
||||||
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
|
dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE)
|
||||||
|
deltas := winDeltas{
|
||||||
|
width: wr.Right,
|
||||||
|
height: wr.Bottom,
|
||||||
|
}
|
||||||
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle)
|
||||||
|
deltas.width = wr.Right - wr.Left - deltas.width
|
||||||
|
deltas.height = wr.Bottom - wr.Top - deltas.height
|
||||||
|
|
||||||
hwnd, err := windows.CreateWindowEx(dwExStyle,
|
hwnd, err := windows.CreateWindowEx(dwExStyle,
|
||||||
resources.class,
|
resources.class,
|
||||||
opts.Title,
|
opts.Title,
|
||||||
@@ -168,7 +198,10 @@ func createNativeWindow(opts *Options) (*window, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
w := &window{
|
w := &window{
|
||||||
hwnd: hwnd,
|
hwnd: hwnd,
|
||||||
|
minmax: getWindowConstraints(cfg, opts, deltas),
|
||||||
|
deltas: deltas,
|
||||||
|
opts: opts,
|
||||||
}
|
}
|
||||||
w.hdc, err = windows.GetDC(hwnd)
|
w.hdc, err = windows.GetDC(hwnd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -251,6 +284,20 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
|
|||||||
case windows.SIZE_MAXIMIZED, windows.SIZE_RESTORED:
|
case windows.SIZE_MAXIMIZED, windows.SIZE_RESTORED:
|
||||||
w.setStage(system.StageRunning)
|
w.setStage(system.StageRunning)
|
||||||
}
|
}
|
||||||
|
case windows.WM_GETMINMAXINFO:
|
||||||
|
mm := (*windows.MinMaxInfo)(unsafe.Pointer(uintptr(lParam)))
|
||||||
|
if w.minmax.minWidth > 0 || w.minmax.minHeight > 0 {
|
||||||
|
mm.PtMinTrackSize = windows.Point{
|
||||||
|
w.minmax.minWidth,
|
||||||
|
w.minmax.minHeight,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if w.minmax.maxWidth > 0 || w.minmax.maxHeight > 0 {
|
||||||
|
mm.PtMaxTrackSize = windows.Point{
|
||||||
|
w.minmax.maxWidth,
|
||||||
|
w.minmax.maxHeight,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return windows.DefWindowProc(hwnd, msg, wParam, lParam)
|
return windows.DefWindowProc(hwnd, msg, wParam, lParam)
|
||||||
@@ -375,6 +422,7 @@ func (w *window) draw(sync bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
cfg := configForDC()
|
cfg := configForDC()
|
||||||
|
w.minmax = getWindowConstraints(cfg, w.opts, w.deltas)
|
||||||
w.w.Event(FrameEvent{
|
w.w.Event(FrameEvent{
|
||||||
FrameEvent: system.FrameEvent{
|
FrameEvent: system.FrameEvent{
|
||||||
Now: time.Now(),
|
Now: time.Now(),
|
||||||
|
|||||||
@@ -514,6 +514,21 @@ func newX11Window(gioWin Callbacks, opts *Options) error {
|
|||||||
hints.flags = C.InputHint
|
hints.flags = C.InputHint
|
||||||
C.XSetWMHints(dpy, win, &hints)
|
C.XSetWMHints(dpy, win, &hints)
|
||||||
|
|
||||||
|
var shints C.XSizeHints
|
||||||
|
if opts.MinWidth.V != 0 || opts.MinHeight.V != 0 {
|
||||||
|
shints.min_width = C.int(cfg.Px(opts.MinWidth))
|
||||||
|
shints.min_height = C.int(cfg.Px(opts.MinHeight))
|
||||||
|
shints.flags = C.PMinSize
|
||||||
|
}
|
||||||
|
if opts.MaxWidth.V != 0 || opts.MaxHeight.V != 0 {
|
||||||
|
shints.max_width = C.int(cfg.Px(opts.MaxWidth))
|
||||||
|
shints.max_height = C.int(cfg.Px(opts.MaxHeight))
|
||||||
|
shints.flags = shints.flags | C.PMaxSize
|
||||||
|
}
|
||||||
|
if shints.flags != 0 {
|
||||||
|
C.XSetWMNormalHints(dpy, win, &shints)
|
||||||
|
}
|
||||||
|
|
||||||
name := C.CString(filepath.Base(os.Args[0]))
|
name := C.CString(filepath.Base(os.Args[0]))
|
||||||
defer C.free(unsafe.Pointer(name))
|
defer C.free(unsafe.Pointer(name))
|
||||||
wmhints := C.XClassHint{name, name}
|
wmhints := C.XClassHint{name, name}
|
||||||
|
|||||||
@@ -14,8 +14,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Options struct {
|
type Options struct {
|
||||||
Width, Height unit.Value
|
Width, Height unit.Value
|
||||||
Title string
|
MinWidth, MinHeight unit.Value
|
||||||
|
MaxWidth, MaxHeight unit.Value
|
||||||
|
Title string
|
||||||
}
|
}
|
||||||
|
|
||||||
type FrameEvent struct {
|
type FrameEvent struct {
|
||||||
|
|||||||
@@ -46,6 +46,14 @@ type Point struct {
|
|||||||
X, Y int32
|
X, Y int32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MinMaxInfo struct {
|
||||||
|
PtReserved Point
|
||||||
|
PtMaxSize Point
|
||||||
|
PtMaxPosition Point
|
||||||
|
PtMinTrackSize Point
|
||||||
|
PtMaxTrackSize Point
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
CS_HREDRAW = 0x0002
|
CS_HREDRAW = 0x0002
|
||||||
CS_VREDRAW = 0x0001
|
CS_VREDRAW = 0x0001
|
||||||
@@ -120,33 +128,34 @@ const (
|
|||||||
|
|
||||||
UNICODE_NOCHAR = 65535
|
UNICODE_NOCHAR = 65535
|
||||||
|
|
||||||
WM_CANCELMODE = 0x001F
|
WM_CANCELMODE = 0x001F
|
||||||
WM_CHAR = 0x0102
|
WM_CHAR = 0x0102
|
||||||
WM_CREATE = 0x0001
|
WM_CREATE = 0x0001
|
||||||
WM_DPICHANGED = 0x02E0
|
WM_DPICHANGED = 0x02E0
|
||||||
WM_DESTROY = 0x0002
|
WM_DESTROY = 0x0002
|
||||||
WM_ERASEBKGND = 0x0014
|
WM_ERASEBKGND = 0x0014
|
||||||
WM_KEYDOWN = 0x0100
|
WM_KEYDOWN = 0x0100
|
||||||
WM_KEYUP = 0x0101
|
WM_KEYUP = 0x0101
|
||||||
WM_LBUTTONDOWN = 0x0201
|
WM_LBUTTONDOWN = 0x0201
|
||||||
WM_LBUTTONUP = 0x0202
|
WM_LBUTTONUP = 0x0202
|
||||||
WM_MBUTTONDOWN = 0x0207
|
WM_MBUTTONDOWN = 0x0207
|
||||||
WM_MBUTTONUP = 0x0208
|
WM_MBUTTONUP = 0x0208
|
||||||
WM_MOUSEMOVE = 0x0200
|
WM_MOUSEMOVE = 0x0200
|
||||||
WM_MOUSEWHEEL = 0x020A
|
WM_MOUSEWHEEL = 0x020A
|
||||||
WM_PAINT = 0x000F
|
WM_PAINT = 0x000F
|
||||||
WM_CLOSE = 0x0010
|
WM_CLOSE = 0x0010
|
||||||
WM_QUIT = 0x0012
|
WM_QUIT = 0x0012
|
||||||
WM_SETFOCUS = 0x0007
|
WM_SETFOCUS = 0x0007
|
||||||
WM_KILLFOCUS = 0x0008
|
WM_KILLFOCUS = 0x0008
|
||||||
WM_SHOWWINDOW = 0x0018
|
WM_SHOWWINDOW = 0x0018
|
||||||
WM_SIZE = 0x0005
|
WM_SIZE = 0x0005
|
||||||
WM_SYSKEYDOWN = 0x0104
|
WM_SYSKEYDOWN = 0x0104
|
||||||
WM_RBUTTONDOWN = 0x0204
|
WM_RBUTTONDOWN = 0x0204
|
||||||
WM_RBUTTONUP = 0x0205
|
WM_RBUTTONUP = 0x0205
|
||||||
WM_TIMER = 0x0113
|
WM_TIMER = 0x0113
|
||||||
WM_UNICHAR = 0x0109
|
WM_UNICHAR = 0x0109
|
||||||
WM_USER = 0x0400
|
WM_USER = 0x0400
|
||||||
|
WM_GETMINMAXINFO = 0x0024
|
||||||
|
|
||||||
WS_CLIPCHILDREN = 0x00010000
|
WS_CLIPCHILDREN = 0x00010000
|
||||||
WS_CLIPSIBLINGS = 0x04000000
|
WS_CLIPSIBLINGS = 0x04000000
|
||||||
|
|||||||
@@ -427,4 +427,32 @@ func Size(w, h unit.Value) Option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaxSize sets the maximum size of the window.
|
||||||
|
func MaxSize(w, h unit.Value) Option {
|
||||||
|
if w.V <= 0 {
|
||||||
|
panic("width must be larger than or equal to 0")
|
||||||
|
}
|
||||||
|
if h.V <= 0 {
|
||||||
|
panic("height must be larger than or equal to 0")
|
||||||
|
}
|
||||||
|
return func(opts *window.Options) {
|
||||||
|
opts.MaxWidth = w
|
||||||
|
opts.MaxHeight = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MinSize sets the minimum size of the window.
|
||||||
|
func MinSize(w, h unit.Value) Option {
|
||||||
|
if w.V <= 0 {
|
||||||
|
panic("width must be larger than or equal to 0")
|
||||||
|
}
|
||||||
|
if h.V <= 0 {
|
||||||
|
panic("height must be larger than or equal to 0")
|
||||||
|
}
|
||||||
|
return func(opts *window.Options) {
|
||||||
|
opts.MinWidth = w
|
||||||
|
opts.MinHeight = h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (driverEvent) ImplementsEvent() {}
|
func (driverEvent) ImplementsEvent() {}
|
||||||
|
|||||||
Reference in New Issue
Block a user