From cc5c71e1cb91979944a23001c75f04d6bf2669d2 Mon Sep 17 00:00:00 2001 From: Alexander Medvednikov Date: Tue, 21 Apr 2026 14:58:08 +0300 Subject: [PATCH] sokol: fix gg unable to prevent resize (fixes #20099) --- vlib/gg/gg.c.v | 30 +++++++++++++++++++++++-- vlib/gg/gg_darwin.m | 14 ++++++++++++ vlib/sokol/sapp/sapp_linux.c.v | 20 +++++++++++++++++ vlib/sokol/sapp/sapp_wayland_linux.v | 32 +++++++++++++++++++++++++++ vlib/sokol/sapp/sapp_x11_linux.v | 33 ++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 2 deletions(-) diff --git a/vlib/gg/gg.c.v b/vlib/gg/gg.c.v index 0501d6b48..3bb45dba5 100644 --- a/vlib/gg/gg.c.v +++ b/vlib/gg/gg.c.v @@ -53,6 +53,7 @@ $if windows { $if macos { fn C.gg_macos_resize_window(window voidptr, width int, height int) + fn C.gg_macos_set_window_resizable(window voidptr, resizable bool) } $if windows { @@ -65,6 +66,7 @@ $if windows { fn C.GetWindowRect(hwnd voidptr, rect &C.RECT) int fn C.GetWindowLongW(hwnd voidptr, index int) i32 + fn C.SetWindowLongW(hwnd voidptr, index int, new_long i32) i32 fn C.AdjustWindowRectEx(rect &C.RECT, style u32, menu int, ex_style u32) int fn C.SetWindowPos(hwnd voidptr, hwnd_insert_after voidptr, x int, y int, cx int, cy int, flags u32) int } @@ -103,8 +105,8 @@ pub struct Config { pub: width int = 800 // desired start width of the window height int = 600 // desired start height of the window - retina bool // TODO: implement or deprecate - resizable bool // TODO: implement or deprecate + retina bool // TODO: implement or deprecate + resizable bool = true // prevent user-initiated resizing when supported by the platform backend user_data voidptr // a custom pointer to the application data/instance. When it is not set explicitly, it will default to a pointer to the current gg.Context instance. font_size int // TODO: implement or deprecate create_window bool // TODO: implement or deprecate @@ -270,6 +272,9 @@ fn gg_init_sokol_window(user_data voidptr) { sgl_desc := sgl.Desc{} sgl.setup(&sgl_desc) ctx.set_scale() + if !ctx.config.resizable { + gg_apply_window_resizable() + } // is_high_dpi := sapp.high_dpi() // fb_w := sapp.width() // fb_h := sapp.height() @@ -635,6 +640,27 @@ fn (mut ctx Context) set_cached_window_size(width int, height int) { ctx.window.height = height } +fn gg_apply_window_resizable() { + $if macos { + window := sapp.macos_get_window() + if window != unsafe { nil } { + C.gg_macos_set_window_resizable(window, false) + } + } $else $if windows { + hwnd := sapp.win32_get_hwnd() + if hwnd == unsafe { nil } { + return + } + mut style := u32(C.GetWindowLongW(hwnd, C.GWL_STYLE)) + style &= ~u32(C.WS_SIZEBOX | C.WS_MAXIMIZEBOX) + C.SetWindowLongW(hwnd, C.GWL_STYLE, i32(style)) + C.SetWindowPos(hwnd, unsafe { nil }, 0, 0, 0, 0, + u32(C.SWP_NOMOVE | C.SWP_NOSIZE | C.SWP_NOZORDER | C.SWP_NOACTIVATE | C.SWP_FRAMECHANGED)) + } $else $if linux { + sapp.set_resizable(false) + } +} + fn gg_resize_window(width int, height int) { if width <= 0 || height <= 0 { return diff --git a/vlib/gg/gg_darwin.m b/vlib/gg/gg_darwin.m index 88e29c68a..8f5c5d9e7 100644 --- a/vlib/gg/gg_darwin.m +++ b/vlib/gg/gg_darwin.m @@ -66,6 +66,20 @@ void gg_macos_resize_window(void *window_ptr, int width, int height) { [window setContentSize:NSMakeSize((CGFloat)width, (CGFloat)height)]; } +void gg_macos_set_window_resizable(void *window_ptr, bool resizable) { + if (window_ptr == nil) { + return; + } + NSWindow *window = (__bridge NSWindow *)window_ptr; + NSWindowStyleMask style = [window styleMask]; + if (resizable) { + style |= NSWindowStyleMaskResizable; + } else { + style &= ~NSWindowStyleMaskResizable; + } + [window setStyleMask:style]; +} + void darwin_draw_string(int x, int y, string s, gg__TextCfg cfg) { NSFont* font = [NSFont userFontOfSize:cfg.size]; // # NSFont* font = [NSFont fontWithName:@"Roboto Mono" size:cfg.size]; diff --git a/vlib/sokol/sapp/sapp_linux.c.v b/vlib/sokol/sapp/sapp_linux.c.v index 9facd0aa3..8f64aeb83 100644 --- a/vlib/sokol/sapp/sapp_linux.c.v +++ b/vlib/sokol/sapp/sapp_linux.c.v @@ -628,9 +628,29 @@ mut: map_state int } +pub struct C.XSizeHintsAspect { +mut: + x int + y int +} + pub struct C.XSizeHints { mut: flags i64 + x int + y int + width int + height int + min_width int + min_height int + max_width int + max_height int + width_inc int + height_inc int + min_aspect C.XSizeHintsAspect + max_aspect C.XSizeHintsAspect + base_width int + base_height int win_gravity int } diff --git a/vlib/sokol/sapp/sapp_wayland_linux.v b/vlib/sokol/sapp/sapp_wayland_linux.v index 4a4b694a4..1e4b9f298 100644 --- a/vlib/sokol/sapp/sapp_wayland_linux.v +++ b/vlib/sokol/sapp/sapp_wayland_linux.v @@ -956,6 +956,38 @@ $if sokol_wayland ? { ]! // === Main Wayland run function === + fn wl_set_resizable(resizable bool) { + if g_sapp_state.wl.xdg_toplevel == unsafe { nil } + || g_sapp_state.wl.surface == unsafe { nil } { + return + } + if resizable { + C.xdg_toplevel_set_min_size(g_sapp_state.wl.xdg_toplevel, 0, 0) + C.xdg_toplevel_set_max_size(g_sapp_state.wl.xdg_toplevel, 0, 0) + } else { + width := if g_sapp_state.window_width > 0 { + g_sapp_state.window_width + } else if g_sapp_state.wl.width > 0 { + g_sapp_state.wl.width + } else { + fallback_default_window_width + } + height := if g_sapp_state.window_height > 0 { + g_sapp_state.window_height + } else if g_sapp_state.wl.height > 0 { + g_sapp_state.wl.height + } else { + fallback_default_window_height + } + C.xdg_toplevel_set_min_size(g_sapp_state.wl.xdg_toplevel, i32(width), i32(height)) + C.xdg_toplevel_set_max_size(g_sapp_state.wl.xdg_toplevel, i32(width), i32(height)) + } + C.wl_surface_commit(g_sapp_state.wl.surface) + if g_sapp_state.wl.display != unsafe { nil } { + C.wl_display_flush(g_sapp_state.wl.display) + } + } + pub fn wl_run(desc &Desc) { sapp_init_state(desc) diff --git a/vlib/sokol/sapp/sapp_x11_linux.v b/vlib/sokol/sapp/sapp_x11_linux.v index 8b4f59924..7c935071a 100644 --- a/vlib/sokol/sapp/sapp_x11_linux.v +++ b/vlib/sokol/sapp/sapp_x11_linux.v @@ -1080,6 +1080,39 @@ fn x11_set_fullscreen(enable bool) { C.XFlush(g_sapp_state.x11.display) } +// set_resizable toggles whether the current Linux window can be resized by the window manager. +pub fn set_resizable(resizable bool) { + $if sokol_wayland ? { + wl_set_resizable(resizable) + } $else { + x11_set_resizable(resizable) + } +} + +fn x11_set_resizable(resizable bool) { + if g_sapp_state.x11.display == unsafe { nil } || g_sapp_state.x11.window == 0 { + return + } + mut hints := C.XAllocSizeHints() + if hints == unsafe { nil } { + return + } + hints.flags = pw_gravity + hints.win_gravity = center_gravity + if !resizable { + mut attribs := C.XWindowAttributes{} + C.XGetWindowAttributes(g_sapp_state.x11.display, g_sapp_state.x11.window, &attribs) + hints.flags |= i64(1 << 4) | i64(1 << 5) // PMinSize | PMaxSize + hints.min_width = attribs.width + hints.min_height = attribs.height + hints.max_width = attribs.width + hints.max_height = attribs.height + } + C.XSetWMNormalHints(g_sapp_state.x11.display, g_sapp_state.x11.window, hints) + C.XFree(hints) + C.XFlush(g_sapp_state.x11.display) +} + fn x11_create_window(visual_ &C.Visual, depth int) { mut vis := unsafe { visual_ } mut dep := depth -- 2.39.5