~pierrec: 1 app/internal/wm: use Option method to initialize windows 10 files changed, 207 insertions(+), 110 deletions(-)
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.sr.ht/~eliasnaur/gio-patches/patches/21748/mbox | git am -3Learn more about email & git
From: pierre <pierre.curto@gmail.com> Added (*w.window).Option methods to the backends and use them for setting the initial options passed into NewWindow. Signed-off-by: pierre <pierre.curto@gmail.com> --- - app/internal/windows/windows.go | 17 ++++++- app/internal/wm/os_android.go | 2 + app/internal/wm/os_ios.go | 2 + app/internal/wm/os_js.go | 10 ++-- app/internal/wm/os_macos.go | 90 ++++++++++++++++++++------------- app/internal/wm/os_macos.m | 25 ++++++++- app/internal/wm/os_wayland.go | 24 +++++---- app/internal/wm/os_windows.go | 66 +++++++++++++++--------- app/internal/wm/os_x11.go | 78 +++++++++++++++------------- app/internal/wm/window.go | 3 ++ 10 files changed, 207 insertions(+), 110 deletions(-) diff --git a/app/internal/windows/windows.go b/app/internal/windows/windows.go index 1601172e..8af575e7 100644 --- a/app/internal/windows/windows.go +++ b/app/internal/windows/windows.go @@ -271,6 +271,7 @@ var ( _LoadImage = user32.NewProc("LoadImageW") _MonitorFromPoint = user32.NewProc("MonitorFromPoint") _MonitorFromWindow = user32.NewProc("MonitorFromWindow") + _MoveWindow = user32.NewProc("MoveWindow") _MsgWaitForMultipleObjectsEx = user32.NewProc("MsgWaitForMultipleObjectsEx") _OpenClipboard = user32.NewProc("OpenClipboard") _PeekMessage = user32.NewProc("PeekMessageW") @@ -289,8 +290,9 @@ var ( _SetProcessDPIAware = user32.NewProc("SetProcessDPIAware") _SetTimer = user32.NewProc("SetTimer") _SetWindowLong = user32.NewProc("SetWindowLongPtrW") - _SetWindowPos = user32.NewProc("SetWindowPos") _SetWindowPlacement = user32.NewProc("SetWindowPlacement") + _SetWindowPos = user32.NewProc("SetWindowPos") + _SetWindowText = user32.NewProc("SetWindowTextW") _TranslateMessage = user32.NewProc("TranslateMessage") _UnregisterClass = user32.NewProc("UnregisterClassW") _UpdateWindow = user32.NewProc("UpdateWindow") @@ -486,6 +488,11 @@ func SetWindowPos(hwnd syscall.Handle, hwndInsertAfter uint32, x, y, dx, dy int3 ) } +func SetWindowText(hwnd syscall.Handle, title string) { + wname := syscall.StringToUTF16Ptr(title) + _SetWindowText.Call(uintptr(hwnd), uintptr(unsafe.Pointer(wname))) +} + func GlobalAlloc(size int) (syscall.Handle, error) { r, _, err := _GlobalAlloc.Call(GHND, uintptr(size)) if r == 0 { @@ -534,6 +541,14 @@ func LoadImage(hInst syscall.Handle, res uint32, typ uint32, cx, cy int, fuload return syscall.Handle(h), nil } +func MoveWindow(hwnd syscall.Handle, x, y, width, height int32, repaint bool) { + var paint uintptr + if repaint { + paint = TRUE + } + _MoveWindow.Call(uintptr(hwnd), uintptr(x), uintptr(y), uintptr(width), uintptr(height), paint) +} + func monitorFromPoint(pt Point, flags uint32) syscall.Handle { r, _, _ := _MonitorFromPoint.Call(uintptr(pt.X), uintptr(pt.Y), uintptr(flags)) return syscall.Handle(r) diff --git a/app/internal/wm/os_android.go b/app/internal/wm/os_android.go index 3b463cdf..287ef5bf 100644 --- a/app/internal/wm/os_android.go +++ b/app/internal/wm/os_android.go @@ -676,6 +676,8 @@ func (w *window) ReadClipboard() { }) } +func (w *window) Option(opts *Options) {} + func (w *window) SetCursor(name pointer.CursorName) { w.setState(func(state *windowState) { state.cursor = &name diff --git a/app/internal/wm/os_ios.go b/app/internal/wm/os_ios.go index a5d023a5..1730af2c 100644 --- a/app/internal/wm/os_ios.go +++ b/app/internal/wm/os_ios.go @@ -239,6 +239,8 @@ func (w *window) WriteClipboard(s string) { }) } +func (w *window) Option(opts *Options) {} + func (w *window) SetAnimating(anim bool) { v := w.view if v == 0 { diff --git a/app/internal/wm/os_js.go b/app/internal/wm/os_js.go index 7eb627b9..b24419a7 100644 --- a/app/internal/wm/os_js.go +++ b/app/internal/wm/os_js.go @@ -82,9 +82,7 @@ func NewWindow(win Callbacks, opts *Options) error { }) w.addEventListeners() w.addHistory() - if o := opts.WindowMode; o != nil { - w.windowMode(*o) - } + w.Option(opts) w.w = win go func() { @@ -476,6 +474,12 @@ func (w *window) WriteClipboard(s string) { w.clipboard.Call("writeText", s) } +func (w *window) Option(opts *Options) { + if o := opts.WindowMode; o != nil { + w.windowMode(*o) + } +} + func (w *window) SetCursor(name pointer.CursorName) { style := w.cnv.Get("style") style.Set("cursor", string(name)) diff --git a/app/internal/wm/os_macos.go b/app/internal/wm/os_macos.go index b82c8d0f..d088a924 100644 --- a/app/internal/wm/os_macos.go +++ b/app/internal/wm/os_macos.go @@ -46,6 +46,10 @@ __attribute__ ((visibility ("hidden"))) CFTypeRef gio_createWindow(CFTypeRef vie __attribute__ ((visibility ("hidden"))) void gio_makeKeyAndOrderFront(CFTypeRef windowRef); __attribute__ ((visibility ("hidden"))) NSPoint gio_cascadeTopLeftFromPoint(CFTypeRef windowRef, NSPoint topLeft); __attribute__ ((visibility ("hidden"))) void gio_close(CFTypeRef windowRef); +__attribute__ ((visibility ("hidden"))) void gio_setSize(CFTypeRef windowRef, CGFloat width, CGFloat height); +__attribute__ ((visibility ("hidden"))) void gio_setMinSize(CFTypeRef windowRef, CGFloat width, CGFloat height); +__attribute__ ((visibility ("hidden"))) void gio_setMaxSize(CFTypeRef windowRef, CGFloat width, CGFloat height); +__attribute__ ((visibility ("hidden"))) void gio_setTitle(CFTypeRef windowRef, const char *title); */ import "C" @@ -126,6 +130,45 @@ func (w *window) WriteClipboard(s string) { }) } +func (w *window) Option(opts *Options) { + w.runOnMain(func() { + screenScale := float32(C.gio_getScreenBackingScale()) + cfg := configFor(screenScale) + val := func(v unit.Value) float32 { + return float32(cfg.Px(v)) / screenScale + } + if o := opts.Size; o != nil { + width := val(o.Width) + height := val(o.Height) + if width > 0 || height > 0 { + C.gio_setSize(w.window, C.CGFloat(width), C.CGFloat(height)) + } + } + if o := opts.MinSize; o != nil { + width := val(o.Width) + height := val(o.Height) + if width > 0 || height > 0 { + C.gio_setMinSize(w.window, C.CGFloat(width), C.CGFloat(height)) + } + } + if o := opts.MaxSize; o != nil { + width := val(o.Width) + height := val(o.Height) + if width > 0 || height > 0 { + C.gio_setMaxSize(w.window, C.CGFloat(width), C.CGFloat(height)) + } + } + if o := opts.Title; o != nil { + title := C.CString(*o) + defer C.free(unsafe.Pointer(title)) + C.gio_setTitle(w.window, title) + } + if o := opts.WindowMode; o != nil { + w.SetWindowMode(*o) + } + }) +} + func (w *window) SetWindowMode(mode WindowMode) { switch mode { case w.mode: @@ -150,16 +193,22 @@ func (w *window) SetAnimating(anim bool) { } } -func (w *window) Close() { +func (w *window) runOnMain(f func()) { runOnMain(func() { // Make sure the view is still valid. The window might've been closed // during the switch to the main thread. if w.view != 0 { - C.gio_close(w.window) + f() } }) } +func (w *window) Close() { + w.runOnMain(func() { + C.gio_close(w.window) + }) +} + func (w *window) setStage(stage system.Stage) { if stage == w.stage { return @@ -336,35 +385,11 @@ func NewWindow(win Callbacks, opts *Options) error { errch <- err return } - screenScale := float32(C.gio_getScreenBackingScale()) - cfg := configFor(screenScale) - // Window sizes is in unscaled screen coordinates, not device pixels. - var width, height int - if o := opts.Size; o != nil { - width = int(float32(cfg.Px(o.Width)) / screenScale) - height = int(float32(cfg.Px(o.Height)) / screenScale) - } - var minWidth, minHeight int - if o := opts.MinSize; o != nil { - minWidth = int(float32(cfg.Px(o.Width)) / screenScale) - minHeight = int(float32(cfg.Px(o.Height)) / screenScale) - } - var maxWidth, maxHeight int - if o := opts.MaxSize; o != nil { - maxWidth = int(float32(cfg.Px(o.Width)) / screenScale) - maxHeight = int(float32(cfg.Px(o.Height)) / screenScale) - } - var title string - if o := opts.Title; o != nil { - title = *o - } - ctitle := C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) errch <- nil win.SetDriver(w) w.w = win - w.window = C.gio_createWindow(w.view, ctitle, C.CGFloat(width), C.CGFloat(height), - C.CGFloat(minWidth), C.CGFloat(minHeight), C.CGFloat(maxWidth), C.CGFloat(maxHeight)) + w.window = C.gio_createWindow(w.view, nil, 0, 0, 0, 0, 0, 0) + w.Option(opts) if nextTopLeft.x == 0 && nextTopLeft.y == 0 { // cascadeTopLeftFromPoint treats (0, 0) as a no-op, // and just returns the offset we need for the first window. @@ -372,9 +397,6 @@ func NewWindow(win Callbacks, opts *Options) error { } nextTopLeft = C.gio_cascadeTopLeftFromPoint(w.window, nextTopLeft) C.gio_makeKeyAndOrderFront(w.window) - if o := opts.WindowMode; o != nil { - w.SetWindowMode(*o) - } }) return <-errch } @@ -390,10 +412,8 @@ func newWindow(opts *Options) (*window, error) { scale: scale, } dl, err := NewDisplayLink(func() { - runOnMain(func() { - if w.view != 0 { - C.gio_setNeedsDisplay(w.view) - } + w.runOnMain(func() { + C.gio_setNeedsDisplay(w.view) }) }) w.displayLink = dl diff --git a/app/internal/wm/os_macos.m b/app/internal/wm/os_macos.m index 24c906cb..7980d532 100644 --- a/app/internal/wm/os_macos.m +++ b/app/internal/wm/os_macos.m @@ -191,7 +191,9 @@ CFTypeRef gio_createWindow(CFTypeRef viewRef, const char *title, CGFloat width, window.contentMaxSize = NSMakeSize(maxWidth, maxHeight); } [window setAcceptsMouseMovedEvents:YES]; - window.title = [NSString stringWithUTF8String: title]; + if (title != nil) { + window.title = [NSString stringWithUTF8String: title]; + } NSView *view = (__bridge NSView *)viewRef; [window setContentView:view]; [window makeFirstResponder:view]; @@ -206,6 +208,27 @@ void gio_close(CFTypeRef windowRef) { [window performClose:nil]; } +void gio_setSize(CFTypeRef windowRef, CGFloat width, CGFloat height) { + NSWindow* window = (__bridge NSWindow *)windowRef; + NSSize size = NSMakeSize(width, height); + [window setContentSize:size]; +} + +void gio_setMinSize(CFTypeRef windowRef, CGFloat width, CGFloat height) { + NSWindow* window = (__bridge NSWindow *)windowRef; + window.contentMinSize = NSMakeSize(width, height); +} + +void gio_setMaxSize(CFTypeRef windowRef, CGFloat width, CGFloat height) { + NSWindow* window = (__bridge NSWindow *)windowRef; + window.contentMaxSize = NSMakeSize(width, height); +} + +void gio_setTitle(CFTypeRef windowRef, const char *title) { + NSWindow* window = (__bridge NSWindow *)windowRef; + window.title = [NSString stringWithUTF8String: title]; +} + @implementation GioAppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)]; diff --git a/app/internal/wm/os_wayland.go b/app/internal/wm/os_wayland.go index 4a52078c..1e8c59d9 100644 --- a/app/internal/wm/os_wayland.go +++ b/app/internal/wm/os_wayland.go @@ -357,17 +357,8 @@ func (d *wlDisplay) createNativeWindow(opts *Options) (*window, error) { C.xdg_surface_add_listener(w.wmSurf, &C.gio_xdg_surface_listener, unsafe.Pointer(w.surf)) C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf)) - if o := opts.Title; o != nil { - title := C.CString(*o) - C.xdg_toplevel_set_title(w.topLvl, title) - C.free(unsafe.Pointer(title)) - } + w.Option(opts) - _, _, cfg := w.config() - if o := opts.Size; o != nil { - w.width = cfg.Px(o.Width) - w.height = cfg.Px(o.Height) - } if d.decor != nil { // Request server side decorations. w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(d.decor, w.topLvl) @@ -918,6 +909,19 @@ func (w *window) WriteClipboard(s string) { w.disp.wakeup() } +func (w *window) Option(opts *Options) { + _, _, cfg := w.config() + if o := opts.Size; o != nil { + w.width = cfg.Px(o.Width) + w.height = cfg.Px(o.Height) + } + if o := opts.Title; o != nil { + title := C.CString(*o) + C.xdg_toplevel_set_title(w.topLvl, title) + C.free(unsafe.Pointer(title)) + } +} + func (w *window) SetCursor(name pointer.CursorName) { if name == pointer.CursorNone { C.wl_pointer_set_cursor(w.disp.seat.pointer, w.serial, nil, 0, 0) diff --git a/app/internal/wm/os_windows.go b/app/internal/wm/os_windows.go index fe2daf4e..611c7cb0 100644 --- a/app/internal/wm/os_windows.go +++ b/app/internal/wm/os_windows.go @@ -116,15 +116,13 @@ func NewWindow(window Callbacks, opts *Options) error { w.w = window w.w.SetDriver(w) defer w.w.Event(system.DestroyEvent{}) + w.Option(opts) windows.ShowWindow(w.hwnd, windows.SW_SHOWDEFAULT) windows.SetForegroundWindow(w.hwnd) windows.SetFocus(w.hwnd) // Since the window class for the cursor is null, // set it here to show the cursor. w.SetCursor(pointer.CursorDefault) - if o := opts.WindowMode; o != nil { - w.SetWindowMode(*o) - } if err := w.loop(); err != nil { panic(err) } @@ -185,33 +183,15 @@ func createNativeWindow(opts *Options) (*window, error) { } dpi := windows.GetSystemDPI() cfg := configForDPI(dpi) - var wr windows.Rect - if o := opts.Size; o != nil { - wr.Right = int32(cfg.Px(o.Width)) - wr.Bottom = int32(cfg.Px(o.Height)) - } dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW) dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE) - deltas := winDeltas{ - width: wr.Right, - height: wr.Bottom, - } - windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle) - deltas.width = wr.Right - wr.Left - deltas.width - deltas.height = wr.Bottom - wr.Top - deltas.height - - var title string - if o := opts.Title; o != nil { - title = *o - } hwnd, err := windows.CreateWindowEx(dwExStyle, resources.class, - title, + "", dwStyle|windows.WS_CLIPSIBLINGS|windows.WS_CLIPCHILDREN, windows.CW_USEDEFAULT, windows.CW_USEDEFAULT, - wr.Right-wr.Left, - wr.Bottom-wr.Top, + windows.CW_USEDEFAULT, windows.CW_USEDEFAULT, 0, 0, resources.handle, @@ -222,7 +202,6 @@ func createNativeWindow(opts *Options) (*window, error) { w := &window{ hwnd: hwnd, minmax: getWindowConstraints(cfg, opts), - deltas: deltas, opts: opts, } w.hdc, err = windows.GetDC(hwnd) @@ -540,6 +519,45 @@ func (w *window) readClipboard() error { return nil } +func (w *window) Option(opts *Options) { + if o := opts.Size; o != nil { + dpi := windows.GetSystemDPI() + cfg := configForDPI(dpi) + width := int32(cfg.Px(o.Width)) + height := int32(cfg.Px(o.Height)) + + // Include the window decorations. + wr := windows.Rect{ + Right: width, + Bottom: height, + } + dwStyle := uint32(windows.WS_OVERLAPPEDWINDOW) + dwExStyle := uint32(windows.WS_EX_APPWINDOW | windows.WS_EX_WINDOWEDGE) + windows.AdjustWindowRectEx(&wr, dwStyle, 0, dwExStyle) + + dw, dh := width, height + width = wr.Right - wr.Left + height = wr.Bottom - wr.Top + w.deltas.width = width - dw + w.deltas.height = height - dh + + w.opts.Size = o + windows.MoveWindow(w.hwnd, 0, 0, width, height, true) + } + if o := opts.MinSize; o != nil { + w.opts.MinSize = o + } + if o := opts.MaxSize; o != nil { + w.opts.MaxSize = o + } + if o := opts.Title; o != nil { + windows.SetWindowText(w.hwnd, *opts.Title) + } + if o := opts.WindowMode; o != nil { + w.SetWindowMode(*o) + } +} + func (w *window) SetWindowMode(mode WindowMode) { // https://devblogs.microsoft.com/oldnewthing/20100412-00/?p=14353 switch mode { diff --git a/app/internal/wm/os_x11.go b/app/internal/wm/os_x11.go index 671fd4a9..b921d468 100644 --- a/app/internal/wm/os_x11.go +++ b/app/internal/wm/os_x11.go @@ -123,6 +123,47 @@ func (w *x11Window) WriteClipboard(s string) { w.wakeup() } +func (w *x11Window) Option(opts *Options) { + dpy := w.x + win := w.xw + cfg := w.cfg + var shints C.XSizeHints + if o := opts.MinSize; o != nil { + shints.min_width = C.int(cfg.Px(o.Width)) + shints.min_height = C.int(cfg.Px(o.Height)) + shints.flags = C.PMinSize + } + if o := opts.MaxSize; o != nil { + shints.max_width = C.int(cfg.Px(o.Width)) + shints.max_height = C.int(cfg.Px(o.Height)) + shints.flags = shints.flags | C.PMaxSize + } + if shints.flags != 0 { + C.XSetWMNormalHints(dpy, win, &shints) + } + + var title string + if o := opts.Title; o != nil { + title = *o + } + ctitle := C.CString(title) + defer C.free(unsafe.Pointer(ctitle)) + C.XStoreName(dpy, win, ctitle) + // set _NET_WM_NAME as well for UTF-8 support in window title. + C.XSetTextProperty(dpy, win, + &C.XTextProperty{ + value: (*C.uchar)(unsafe.Pointer(ctitle)), + encoding: w.atoms.utf8string, + format: 8, + nitems: C.ulong(len(title)), + }, + w.atoms.wmName) + + if o := opts.WindowMode; o != nil { + w.SetWindowMode(*o) + } +} + func (w *x11Window) SetCursor(name pointer.CursorName) { switch name { case pointer.CursorNone: @@ -607,21 +648,6 @@ func newX11Window(gioWin Callbacks, opts *Options) error { hints.flags = C.InputHint C.XSetWMHints(dpy, win, &hints) - var shints C.XSizeHints - if o := opts.MinSize; o != nil && (o.Width.V != 0 || o.Height.V != 0) { - shints.min_width = C.int(cfg.Px(o.Width)) - shints.min_height = C.int(cfg.Px(o.Height)) - shints.flags = C.PMinSize - } - if o := opts.MaxSize; o != nil && (o.Width.V != 0 || o.Height.V != 0) { - shints.max_width = C.int(cfg.Px(o.Width)) - shints.max_height = C.int(cfg.Px(o.Height)) - shints.flags = shints.flags | C.PMaxSize - } - if shints.flags != 0 { - C.XSetWMNormalHints(dpy, win, &shints) - } - name := C.CString(filepath.Base(os.Args[0])) defer C.free(unsafe.Pointer(name)) wmhints := C.XClassHint{name, name} @@ -639,30 +665,10 @@ func newX11Window(gioWin Callbacks, opts *Options) error { w.atoms.wmState = w.atom("_NET_WM_STATE", false) w.atoms.wmStateFullscreen = w.atom("_NET_WM_STATE_FULLSCREEN", false) - // set the name - var title string - if o := opts.Title; o != nil { - title = *o - } - ctitle := C.CString(title) - defer C.free(unsafe.Pointer(ctitle)) - C.XStoreName(dpy, win, ctitle) - // set _NET_WM_NAME as well for UTF-8 support in window title. - C.XSetTextProperty(dpy, win, - &C.XTextProperty{ - value: (*C.uchar)(unsafe.Pointer(ctitle)), - encoding: w.atoms.utf8string, - format: 8, - nitems: C.ulong(len(title)), - }, - w.atoms.wmName) - // extensions C.XSetWMProtocols(dpy, win, &w.atoms.evDelWindow, 1) - if o := opts.WindowMode; o != nil { - w.SetWindowMode(*o) - } + w.Option(opts) // make the window visible on the screen C.XMapWindow(dpy, win) diff --git a/app/internal/wm/window.go b/app/internal/wm/window.go index 7eb51f2d..168d4d6d 100644 --- a/app/internal/wm/window.go +++ b/app/internal/wm/window.go @@ -74,6 +74,9 @@ type Driver interface { // WriteClipboard requests a clipboard write. WriteClipboard(s string) + // Option processes option changes. + Option(opts *Options) + // SetCursor updates the current cursor to name. SetCursor(name pointer.CursorName) -- 2.30.2
builds.sr.htgio/patches: SUCCESS in 36m10s [app/internal/wm: use Option method to initialize windows][0] from [~pierrec][1] [0]: https://lists.sr.ht/~eliasnaur/gio-patches/patches/21748 [1]: mailto:pierre.curto@gmail.com ✓ #475707 SUCCESS gio/patches/linux.yml https://builds.sr.ht/~eliasnaur/job/475707 ✓ #475708 SUCCESS gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/475708 ✓ #475706 SUCCESS gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/475706 ✓ #475705 SUCCESS gio/patches/apple.yml https://builds.sr.ht/~eliasnaur/job/475705
Thanks, merged. Elias