~eliasnaur/gio-patches

gio: app: support changing Window options at runtime v1 PROPOSED

~pierrec
~pierrec: 1
 app: support changing Window options at runtime

 5 files changed, 95 insertions(+), 14 deletions(-)
#479573 apple.yml success
#479574 freebsd.yml success
#479575 linux.yml success
#479576 openbsd.yml success
Great!

Now, how do you see manipulating the window options from ops?
A WindowOptionOp in the op package for instance?
Le mer. 7 avr. 2021 à 09:25, Elias Naur <mail@eliasnaur.com> a écrit :
Le mer. 7 avr. 2021 à 09:58, Elias Naur <mail@eliasnaur.com> a écrit :
Next
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~eliasnaur/gio-patches/patches/21862/mbox | git am -3
Learn more about email & git
View this thread in the archives

[PATCH gio] app: support changing Window options at runtime Export this patch

~pierrec
From: pierre <pierre.curto@gmail.com>

A Window can now be requested to change its options after
it has been started via its Option method.

All options are supported on macOS, Windows and X11.
On Wayland, only the Size and Title options can be changed
at runtime.

Signed-off-by: pierre <pierre.curto@gmail.com>
---
-

 app/internal/wm/os_macos.go   |  5 ++-
 app/internal/wm/os_wayland.go | 15 ++++++++-
 app/internal/wm/os_windows.go | 15 +++++++++
 app/internal/wm/os_x11.go     | 63 +++++++++++++++++++++++++++++------
 app/window.go                 | 11 ++++++
 5 files changed, 95 insertions(+), 14 deletions(-)

diff --git a/app/internal/wm/os_macos.go b/app/internal/wm/os_macos.go
index d088a924..b9266d83 100644
--- a/app/internal/wm/os_macos.go
+++ b/app/internal/wm/os_macos.go
@@ -172,11 +172,10 @@ func (w *window) Option(opts *Options) {
func (w *window) SetWindowMode(mode WindowMode) {
	switch mode {
	case w.mode:
		return
	case Fullscreen:
	case Windowed, Fullscreen:
		C.gio_toggleFullScreen(w.window)
		w.mode = mode
	}
	w.mode = mode
}

func (w *window) SetCursor(name pointer.CursorName) {
diff --git a/app/internal/wm/os_wayland.go b/app/internal/wm/os_wayland.go
index 1e8c59d9..03790959 100644
--- a/app/internal/wm/os_wayland.go
+++ b/app/internal/wm/os_wayland.go
@@ -181,6 +181,7 @@ type window struct {

	mu        sync.Mutex
	animating bool
	opts      *Options
	needAck   bool
	// The most recent configure serial waiting to be ack'ed.
	serial   C.uint32_t
@@ -357,7 +358,7 @@ 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))

	w.Option(opts)
	w.setOptions(opts)

	if d.decor != nil {
		// Request server side decorations.
@@ -910,6 +911,13 @@ func (w *window) WriteClipboard(s string) {
}

func (w *window) Option(opts *Options) {
	w.mu.Lock()
	w.opts = opts
	w.mu.Unlock()
	w.disp.wakeup()
}

func (w *window) setOptions(opts *Options) {
	_, _, cfg := w.config()
	if o := opts.Size; o != nil {
		w.width = cfg.Px(o.Width)
@@ -1143,8 +1151,10 @@ func (w *window) process() {
	w.mu.Lock()
	readClipboard := w.readClipboard
	writeClipboard := w.writeClipboard
	opts := w.opts
	w.readClipboard = false
	w.writeClipboard = nil
	w.opts = nil
	w.mu.Unlock()
	if readClipboard {
		r, err := w.disp.readClipboard()
@@ -1163,6 +1173,9 @@ func (w *window) process() {
	if writeClipboard != nil {
		w.disp.writeClipboard([]byte(*writeClipboard))
	}
	if opts != nil {
		w.setOptions(opts)
	}
	// pass false to skip unnecessary drawing.
	w.draw(false)
}
diff --git a/app/internal/wm/os_windows.go b/app/internal/wm/os_windows.go
index 611c7cb0..05d440ea 100644
--- a/app/internal/wm/os_windows.go
+++ b/app/internal/wm/os_windows.go
@@ -66,6 +66,7 @@ type window struct {
const (
	_WM_REDRAW = windows.WM_USER + iota
	_WM_CURSOR
	_WM_OPTION
)

type gpuAPI struct {
@@ -317,6 +318,8 @@ func windowProc(hwnd syscall.Handle, msg uint32, wParam, lParam uintptr) uintptr
			windows.SetCursor(w.cursor)
			return windows.TRUE
		}
	case _WM_OPTION:
		w.setOptions()
	}

	return windows.DefWindowProc(hwnd, msg, wParam, lParam)
@@ -520,6 +523,18 @@ func (w *window) readClipboard() error {
}

func (w *window) Option(opts *Options) {
	w.mu.Lock()
	w.opts = opts
	w.mu.Unlock()
	if err := windows.PostMessage(w.hwnd, _WM_OPTION, 0, 0); err != nil {
		panic(err)
	}
}

func (w *window) setOptions() {
	w.mu.Lock()
	opts := w.opts
	w.mu.Unlock()
	if o := opts.Size; o != nil {
		dpi := windows.GetSystemDPI()
		cfg := configForDPI(dpi)
diff --git a/app/internal/wm/os_x11.go b/app/internal/wm/os_x11.go
index b921d468..75b956e2 100644
--- a/app/internal/wm/os_x11.go
+++ b/app/internal/wm/os_x11.go
@@ -89,6 +89,7 @@ type x11Window struct {

	mu        sync.Mutex
	animating bool
	opts      *Options

	pointerBtns pointer.Buttons

@@ -98,6 +99,7 @@ type x11Window struct {
		content []byte
	}
	cursor pointer.CursorName
	mode   WindowMode
}

func (w *x11Window) SetAnimating(anim bool) {
@@ -124,22 +126,33 @@ func (w *x11Window) WriteClipboard(s string) {
}

func (w *x11Window) Option(opts *Options) {
	dpy := w.x
	win := w.xw
	cfg := w.cfg
	w.mu.Lock()
	w.opts = opts
	w.mu.Unlock()
	w.wakeup()
}

func (w *x11Window) setOptions() {
	w.mu.Lock()
	opts := w.opts
	w.opts = nil
	w.mu.Unlock()
	if opts == nil {
		return
	}
	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.min_width = C.int(w.cfg.Px(o.Width))
		shints.min_height = C.int(w.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.max_width = C.int(w.cfg.Px(o.Width))
		shints.max_height = C.int(w.cfg.Px(o.Height))
		shints.flags = shints.flags | C.PMaxSize
	}
	if shints.flags != 0 {
		C.XSetWMNormalHints(dpy, win, &shints)
		C.XSetWMNormalHints(w.x, w.xw, &shints)
	}

	var title string
@@ -148,9 +161,9 @@ func (w *x11Window) Option(opts *Options) {
	}
	ctitle := C.CString(title)
	defer C.free(unsafe.Pointer(ctitle))
	C.XStoreName(dpy, win, ctitle)
	C.XStoreName(w.x, w.xw, ctitle)
	// set _NET_WM_NAME as well for UTF-8 support in window title.
	C.XSetTextProperty(dpy, win,
	C.XSetTextProperty(w.x, w.xw,
		&C.XTextProperty{
			value:    (*C.uchar)(unsafe.Pointer(ctitle)),
			encoding: w.atoms.utf8string,
@@ -190,6 +203,8 @@ func (w *x11Window) SetCursor(name pointer.CursorName) {

func (w *x11Window) SetWindowMode(mode WindowMode) {
	switch mode {
	case w.mode:
		return
	case Windowed:
		C.XDeleteProperty(w.x, w.xw, w.atoms.wmStateFullscreen)
	case Fullscreen:
@@ -197,7 +212,34 @@ func (w *x11Window) SetWindowMode(mode WindowMode) {
			32, C.PropModeReplace,
			(*C.uchar)(unsafe.Pointer(&w.atoms.wmStateFullscreen)), 1,
		)
	default:
		return
	}
	w.mode = mode
	// "A Client wishing to change the state of a window MUST send
	//  a _NET_WM_STATE client message to the root window (see below)."
	var xev C.XEvent
	ev := (*C.XClientMessageEvent)(unsafe.Pointer(&xev))
	*ev = C.XClientMessageEvent{
		_type:        C.ClientMessage,
		display:      w.x,
		window:       w.xw,
		message_type: w.atoms.wmState,
		format:       32,
	}
	arr := (*[5]C.long)(unsafe.Pointer(&ev.data))
	arr[0] = 2 // _NET_WM_STATE_TOGGLE
	arr[1] = C.long(w.atoms.wmStateFullscreen)
	arr[2] = 0
	arr[3] = 1 // application
	arr[4] = 0
	C.XSendEvent(
		w.x,
		C.XDefaultRootWindow(w.x), // MUST be the root window
		C.False,
		C.SubstructureNotifyMask|C.SubstructureRedirectMask,
		&xev,
	)
}

func (w *x11Window) ShowTextInput(show bool) {}
@@ -287,6 +329,7 @@ loop:
				}
			}
		}
		w.setOptions()
		// Clear notifications.
		for {
			_, err := syscall.Read(w.notify.read, buf)
diff --git a/app/window.go b/app/window.go
index e8f691a9..20ee8b07 100644
--- a/app/window.go
+++ b/app/window.go
@@ -211,6 +211,17 @@ func (w *Window) Invalidate() {
	}
}

// Option applies the options to the window.
func (w *Window) Option(opts ...Option) {
	go w.driverDo(func() {
		o := new(wm.Options)
		for _, opt := range opts {
			opt(o)
		}
		w.driver.Option(o)
	})
}

// ReadClipboard initiates a read of the clipboard in the form
// of a clipboard.Event. Multiple reads may be coalesced
// to a single event.
-- 
2.30.2
builds.sr.ht
gio/patches: SUCCESS in 22m37s

[app: support changing Window options at runtime][0] from [~pierrec][1]

[0]: https://lists.sr.ht/~eliasnaur/gio-patches/patches/21862
[1]: mailto:pierre.curto@gmail.com

✓ #479574 SUCCESS gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/479574
✓ #479575 SUCCESS gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/479575
✓ #479576 SUCCESS gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/479576
✓ #479573 SUCCESS gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/479573
Thanks, merged.

Elias