~eliasnaur/gio-patches

gio: app: use material.Decorations on undecorated platforms v1 PROPOSED

~pierrec: 3
 app: use material.Decorations on undecorated platforms
 [Wayland] set app.Config.Decorated according to the Wayland server decorations requests
 app: swapped the Wayland and X11 drivers

 12 files changed, 248 insertions(+), 12 deletions(-)
#680603 apple.yml failed
#680604 freebsd.yml success
#680605 linux.yml success
#680606 openbsd.yml success
gio/patches: FAILED in 20m47s

[app: use material.Decorations on undecorated platforms][0] from [~pierrec][1]

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

✗ #680603 FAILED  gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/680603
✓ #680606 SUCCESS gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/680606
✓ #680605 SUCCESS gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/680605
✓ #680604 SUCCESS gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/680604
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/28709/mbox | git am -3
Learn more about email & git

[PATCH gio 1/3] app: use material.Decorations on undecorated platforms Export this patch

From: Pierre Curto <pierre.curto@gmail.com>

This patch implements a mechanism for customizing window
decorations.
If a window is configured with app.Decorated(true), then
the widget/material.Decorations are applied. On Wayland,
the option is automatically set when the server does not
provide window decorations.

References: https://todo.sr.ht/~eliasnaur/gio/318
Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
---
 app/os.go         | 14 ++++++++
 app/os_android.go |  8 +++++
 app/os_ios.go     | 14 +++++++-
 app/os_js.go      |  8 +++++
 app/os_macos.go   |  7 ++++
 app/os_wayland.go | 82 ++++++++++++++++++++++++++++++++++++++++---
 app/os_windows.go |  4 +++
 app/os_x11.go     |  7 ++++
 app/window.go     | 89 +++++++++++++++++++++++++++++++++++++++++++++--
 9 files changed, 224 insertions(+), 9 deletions(-)

diff --git a/app/os.go b/app/os.go
index 329f86d0..e44b0d51 100644
--- a/app/os.go
+++ b/app/os.go
@@ -43,6 +43,8 @@ type Config struct {
	CustomRenderer bool
	// center is a flag used to center the window. Set by option.
	center bool
	// Decorated reports whether window decorations are provided automatically.
	Decorated bool
}

// ConfigEvent is sent whenever the configuration of a Window changes.
@@ -177,6 +179,9 @@ type driver interface {

	// Wakeup wakes up the event loop and sends a WakeupEvent.
	Wakeup()

	// Perform actions on the window.
	Perform(system.Action)
}

type windowRendezvous struct {
@@ -218,3 +223,12 @@ func newWindowRendezvous() *windowRendezvous {

func (wakeupEvent) ImplementsEvent() {}
func (ConfigEvent) ImplementsEvent() {}

func walkActions(actions system.Action, do func(system.Action)) {
	for a := system.Action(1); actions != 0; a <<= 1 {
		if actions&a != 0 {
			actions &^= a
			do(a)
		}
	}
}
diff --git a/app/os_android.go b/app/os_android.go
index f835cbdb..f3529422 100644
--- a/app/os_android.go
+++ b/app/os_android.go
@@ -1166,6 +1166,9 @@ func (w *window) Configure(options []Option) {
		prev := w.config
		cnf := w.config
		cnf.apply(unit.Metric{}, options)
		// Decorations are never disabled.
		cnf.Decorated = true

		if prev.Orientation != cnf.Orientation {
			w.config.Orientation = cnf.Orientation
			setOrientation(env, w.view, cnf.Orientation)
@@ -1188,12 +1191,17 @@ func (w *window) Configure(options []Option) {
				w.config.Mode = Windowed
			}
		}
		if cnf.Decorated != prev.Decorated {
			w.config.Decorated = cnf.Decorated
		}
		if w.config != prev {
			w.callbacks.Event(ConfigEvent{Config: w.config})
		}
	})
}

func (w *window) Perform(system.Action) {}

func (w *window) Raise() {}

func (w *window) SetCursor(name pointer.CursorName) {
diff --git a/app/os_ios.go b/app/os_ios.go
index 3e8c3ba1..d7f3a6e3 100644
--- a/app/os_ios.go
+++ b/app/os_ios.go
@@ -273,7 +273,19 @@ func (w *window) WriteClipboard(s string) {
	C.writeClipboard(chars, C.NSUInteger(len(u16)))
}

func (w *window) Configure([]Option) {}
func (w *window) Configure([]Option) {
	prev := w.config
	// Decorations are never disabled.
	w.config.Decorated = true
	if cnf.Decorated != prev.Decorated {
		w.config.Decorated = cnf.Decorated
	}
	if w.config != prev {
		w.w.Event(ConfigEvent{Config: w.config})
	}
}

func (w *window) Perform(system.Action) {}

func (w *window) Raise() {}

diff --git a/app/os_js.go b/app/os_js.go
index 23e49a99..728ca14a 100644
--- a/app/os_js.go
+++ b/app/os_js.go
@@ -513,6 +513,9 @@ func (w *window) Configure(options []Option) {
	prev := w.config
	cnf := w.config
	cnf.apply(unit.Metric{}, options)
	// Decorations are never disabled.
	cnf.Decorated = true

	if prev.Title != cnf.Title {
		w.config.Title = cnf.Title
		w.document.Set("title", cnf.Title)
@@ -528,11 +531,16 @@ func (w *window) Configure(options []Option) {
		w.config.Orientation = cnf.Orientation
		w.orientation(cnf.Orientation)
	}
	if cnf.Decorated != prev.Decorated {
		w.config.Decorated = cnf.Decorated
	}
	if w.config != prev {
		w.w.Event(ConfigEvent{Config: w.config})
	}
}

func (w *window) Perform(system.Action) {}

func (w *window) Raise() {}

func (w *window) SetCursor(name pointer.CursorName) {
diff --git a/app/os_macos.go b/app/os_macos.go
index 10feab26..67b17b1e 100644
--- a/app/os_macos.go
+++ b/app/os_macos.go
@@ -261,6 +261,8 @@ func (w *window) Configure(options []Option) {
	cnf.Size = cnf.Size.Div(int(screenScale))
	cnf.MinSize = cnf.MinSize.Div(int(screenScale))
	cnf.MaxSize = cnf.MaxSize.Div(int(screenScale))
	// Decorations are never disabled.
	cnf.Decorated = true

	switch cnf.Mode {
	case Fullscreen:
@@ -325,6 +327,9 @@ func (w *window) Configure(options []Option) {
			C.setScreenFrame(w.window, C.CGFloat(x), C.CGFloat(y), C.CGFloat(sz.X), C.CGFloat(sz.Y))
		}
	}
	if cnf.Decorated != prev.Decorated {
		w.config.Decorated = cnf.Decorated
	}
	if w.config != prev {
		w.w.Event(ConfigEvent{Config: w.config})
	}
@@ -339,6 +344,8 @@ func (w *window) setTitle(prev, cnf Config) {
	}
}

func (w *window) Perform(system.Action) {}

func (w *window) SetCursor(name pointer.CursorName) {
	w.cursor = windowSetCursor(w.cursor, name)
}
diff --git a/app/os_wayland.go b/app/os_wayland.go
index ed103694..d958b55e 100644
--- a/app/os_wayland.go
+++ b/app/os_wayland.go
@@ -149,6 +149,7 @@ type repeatState struct {
type window struct {
	w          *callbacks
	disp       *wlDisplay
	seat       *wlSeat
	surf       *C.struct_wl_surface
	wmSurf     *C.struct_xdg_surface
	topLvl     *C.struct_xdg_toplevel
@@ -188,9 +189,10 @@ type window struct {
	newScale bool
	scale    int
	// size is the unscaled window size (unlike config.Size which is scaled).
	size   image.Point
	config Config
	wsize  image.Point // window config size before going fullscreen
	size         image.Point
	config       Config
	wsize        image.Point // window config size before going fullscreen or maximized
	inCompositor bool        // window is moving or being resized

	wakeups chan struct{}
}
@@ -212,7 +214,7 @@ type wlOutput struct {
}

// callbackMap maps Wayland native handles to corresponding Go
// references. It is necessary because the the Wayland client API
// references. It is necessary because the Wayland client API
// forces the use of callbacks and storing pointers to Go values
// in C is forbidden.
var callbackMap sync.Map
@@ -499,6 +501,7 @@ func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel,
		w.size = image.Pt(int(width), int(height))
		w.updateOpaqueRegion()
	}
	w.needAck = true
}

//export gio_onOutputMode
@@ -772,15 +775,22 @@ func gio_onPointerEnter(data unsafe.Pointer, pointer *C.struct_wl_pointer, seria
	s := callbackLoad(data).(*wlSeat)
	s.serial = serial
	w := callbackLoad(unsafe.Pointer(surf)).(*window)
	w.seat = s
	s.pointerFocus = w
	w.setCursor(pointer, serial)
	w.lastPos = f32.Point{X: fromFixed(x), Y: fromFixed(y)}
}

//export gio_onPointerLeave
func gio_onPointerLeave(data unsafe.Pointer, p *C.struct_wl_pointer, serial C.uint32_t, surface *C.struct_wl_surface) {
func gio_onPointerLeave(data unsafe.Pointer, p *C.struct_wl_pointer, serial C.uint32_t, surf *C.struct_wl_surface) {
	w := callbackLoad(unsafe.Pointer(surf)).(*window)
	w.seat = nil
	s := callbackLoad(data).(*wlSeat)
	s.serial = serial
	if w.inCompositor {
		w.inCompositor = false
		w.w.Event(pointer.Event{Type: pointer.Cancel})
	}
}

//export gio_onPointerMotion
@@ -818,6 +828,8 @@ func gio_onPointerButton(data unsafe.Pointer, p *C.struct_wl_pointer, serial, t,
	case 0:
		w.pointerBtns &^= btn
		typ = pointer.Release
		// Move or resize gestures no longer applies.
		w.inCompositor = false
	case 1:
		w.pointerBtns |= btn
		typ = pointer.Press
@@ -978,6 +990,9 @@ func (w *window) Configure(options []Option) {
			C.xdg_toplevel_set_max_size(w.topLvl, C.int32_t(cnf.MaxSize.X), C.int32_t(cnf.MaxSize.Y))
		}
	}
	if cnf.Decorated != prev.Decorated {
		w.config.Decorated = cnf.Decorated
	}
	if w.config != prev {
		w.w.Event(ConfigEvent{Config: w.config})
	}
@@ -992,6 +1007,63 @@ func (w *window) setTitle(prev, cnf Config) {
	}
}

func (w *window) Perform(actions system.Action) {
	walkActions(actions, func(action system.Action) {
		switch action {
		case system.ActionMinimize:
			w.Configure([]Option{Minimized.Option()})
		case system.ActionMaximize:
			w.Configure([]Option{Maximized.Option()})
		case system.ActionUnmaximize:
			w.Configure([]Option{Windowed.Option()})
		case system.ActionClose:
			w.Close()
		case system.ActionMove:
			w.move()
		default:
			w.resize(action)
		}
	})
}

func (w *window) move() {
	if !w.inCompositor && w.seat != nil {
		w.inCompositor = true
		s := w.seat
		C.xdg_toplevel_move(w.topLvl, s.seat, s.serial)
	}
}

func (w *window) resize(a system.Action) {
	if w.inCompositor || w.seat == nil {
		return
	}
	var edge int
	switch a {
	case system.ActionResizeNorth:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP
	case system.ActionResizeSouth:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM
	case system.ActionResizeEast:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_LEFT
	case system.ActionResizeWest:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_RIGHT
	case system.ActionResizeNorthWest:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT
	case system.ActionResizeNorthEast:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT
	case system.ActionResizeSouthEast:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT
	case system.ActionResizeSouthWest:
		edge = C.XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT
	default:
		return
	}
	w.inCompositor = true
	s := w.seat
	C.xdg_toplevel_resize(w.topLvl, s.seat, s.serial, C.uint32_t(edge))
}

func (w *window) Raise() {
	// NB. there is no way for a minimized window to be unminimized.
	// https://wayland.app/protocols/xdg-shell#xdg_toplevel:request:set_minimized
diff --git a/app/os_windows.go b/app/os_windows.go
index 9a9028c7..f453c7d4 100644
--- a/app/os_windows.go
+++ b/app/os_windows.go
@@ -531,6 +531,8 @@ func (w *window) Configure(options []Option) {
	metric := configForDPI(dpi)
	w.config.apply(metric, options)
	windows.SetWindowText(w.hwnd, w.config.Title)
	// Decorations are never disabled.
	w.config.Decorated = true

	switch w.config.Mode {
	case Minimized:
@@ -691,6 +693,8 @@ func (w *window) Close() {
	windows.PostMessage(w.hwnd, windows.WM_CLOSE, 0, 0)
}

func (w *window) Perform(system.Action) {}

func (w *window) Raise() {
	windows.SetForegroundWindow(w.hwnd)
	windows.SetWindowPos(w.hwnd, windows.HWND_TOPMOST, 0, 0, 0, 0,
diff --git a/app/os_x11.go b/app/os_x11.go
index 97525bec..a65f637c 100644
--- a/app/os_x11.go
+++ b/app/os_x11.go
@@ -160,6 +160,8 @@ func (w *x11Window) Configure(options []Option) {
	prev := w.config
	cnf := w.config
	cnf.apply(w.metric, options)
	// Decorations are never disabled.
	cnf.Decorated = true

	switch cnf.Mode {
	case Fullscreen:
@@ -241,6 +243,9 @@ func (w *x11Window) Configure(options []Option) {
			C.XMoveResizeWindow(w.x, w.xw, C.int(x), C.int(y), C.uint(sz.X), C.uint(sz.Y))
		}
	}
	if cnf.Decorated != prev.Decorated {
		w.config.Decorated = cnf.Decorated
	}
	if w.config != prev {
		w.w.Event(ConfigEvent{Config: w.config})
	}
@@ -264,6 +269,8 @@ func (w *x11Window) setTitle(prev, cnf Config) {
	}
}

func (w *x11Window) Perform(system.Action) {}

func (w *x11Window) Raise() {
	var xev C.XEvent
	ev := (*C.XClientMessageEvent)(unsafe.Pointer(&xev))
diff --git a/app/window.go b/app/window.go
index 8a4259d3..dc1576ee 100644
--- a/app/window.go
+++ b/app/window.go
@@ -11,14 +11,18 @@ import (
	"time"

	"gioui.org/f32"
	"gioui.org/font/gofont"
	"gioui.org/gpu"
	"gioui.org/internal/ops"
	"gioui.org/io/event"
	"gioui.org/io/pointer"
	"gioui.org/io/profile"
	"gioui.org/io/router"
	"gioui.org/io/system"
	"gioui.org/layout"
	"gioui.org/op"
	"gioui.org/unit"
	"gioui.org/widget/material"

	_ "gioui.org/app/internal/log"
)
@@ -59,8 +63,13 @@ type Window struct {
	nextFrame    time.Time
	delayedDraw  *time.Timer

	queue  queue
	cursor pointer.CursorName
	queue       queue
	cursor      pointer.CursorName
	decorations struct {
		op.Ops
		Config
		*material.Decorations
	}

	callbacks callbacks

@@ -574,9 +583,19 @@ func (w *Window) processEvent(d driver, e event.Event) {
		w.hasNextFrame = false
		e2.Frame = w.update
		e2.Queue = &w.queue

		// Prepare the decorations and update the frame insets.
		wrapper := &w.decorations.Ops
		wrapper.Reset()
		decoRec := op.Record(wrapper)
		e2.FrameEvent.Insets = w.decorate(d, e2.FrameEvent, wrapper)
		op.Defer(wrapper, decoRec.Stop())

		w.out <- e2.FrameEvent
		frame, gotFrame := w.waitFrame()
		err := w.validateAndProcess(d, e2.Size, e2.Sync, frame)
		ops.AddCall(&wrapper.Internal, &frame.Internal, ops.PC{}, ops.PCFor(&frame.Internal))

		err := w.validateAndProcess(d, e2.Size, e2.Sync, wrapper)
		if gotFrame {
			// We're done with frame, let the client continue.
			w.frameAck <- struct{}{}
@@ -602,6 +621,9 @@ func (w *Window) processEvent(d driver, e event.Event) {
		w.out <- e2
		w.waitAck()
	case wakeupEvent:
	case ConfigEvent:
		w.decorations.Config = e2.Config
		w.out <- e
	case event.Event:
		if w.queue.q.Queue(e2) {
			w.setNextFrame(time.Time{})
@@ -660,6 +682,59 @@ func (w *Window) updateCursor(d driver) {
	}
}

// decorate the window if enabled and returns the corresponding Insets.
func (w *Window) decorate(d driver, e system.FrameEvent, o *op.Ops) system.Insets {
	if w.decorations.Config.Decorated || w.decorations.Config.Mode == Fullscreen {
		return e.Insets
	}
	deco := w.decorations.Decorations
	if deco == nil {
		theme := material.NewTheme(gofont.Collection())
		allActions := system.ActionMinimize | system.ActionMaximize | system.ActionUnmaximize |
			system.ActionClose | system.ActionMove |
			system.ActionResizeNorth | system.ActionResizeSouth |
			system.ActionResizeWest | system.ActionResizeEast |
			system.ActionResizeNorthWest | system.ActionResizeSouthWest |
			system.ActionResizeNorthEast | system.ActionResizeSouthEast
		deco = &material.Decorations{
			DecorationsStyle: material.Decorate(theme, allActions),
		}
		w.decorations.Decorations = deco
	}
	// Update the decorations based on the current window mode.
	var actions system.Action
	switch m := w.decorations.Config.Mode; m {
	case Windowed:
		actions |= system.ActionUnmaximize
	case Minimized:
		actions |= system.ActionMinimize
	case Maximized:
		actions |= system.ActionMaximize
	case Fullscreen:
		actions |= system.ActionFullscreen
	default:
		panic(fmt.Sprintf("unknown WindowMode %v", m))
	}
	deco.Perform(actions)
	// Update the window based on the actions on the decorations.
	d.Perform(deco.Actions())

	gtx := layout.Context{
		Ops:         o,
		Now:         e.Now,
		Queue:       e.Queue,
		Metric:      e.Metric,
		Constraints: layout.Exact(e.Size),
	}
	insets := deco.Decorate(gtx, w.decorations.Config.Title)
	return system.Insets{
		Top:    unit.Add(e.Metric, e.Insets.Top, insets.Top),
		Bottom: unit.Add(e.Metric, e.Insets.Bottom, insets.Bottom),
		Left:   unit.Add(e.Metric, e.Insets.Left, insets.Left),
		Right:  unit.Add(e.Metric, e.Insets.Right, insets.Right),
	}
}

// Raise requests that the platform bring this window to the top of all open windows.
// Some platforms do not allow this except under certain circumstances, such as when
// a window from the same application already has focus. If the platform does not
@@ -760,3 +835,11 @@ func CustomRenderer(custom bool) Option {
		cnf.CustomRenderer = custom
	}
}

// Decorated controls whether automatic window decorations
// are enabled.
func Decorated(enabled bool) Option {
	return func(_ unit.Metric, cnf *Config) {
		cnf.Decorated = enabled
	}
}
-- 
2.32.0

[PATCH gio 2/3] [Wayland] set app.Config.Decorated according to the Wayland server decorations requests Export this patch

From: Pierre Curto <pierre.curto@gmail.com>

Server side decorations are no longer requested.
The Decorated flag is set according to the
server's requests.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
---
 app/os_wayland.c  |  5 +++++
 app/os_wayland.go | 20 ++++++++++++++++++--
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/app/os_wayland.c b/app/os_wayland.c
index b137e1f9..a9752aaa 100644
--- a/app/os_wayland.c
+++ b/app/os_wayland.c
@@ -6,6 +6,7 @@

#include <wayland-client.h>
#include "wayland_xdg_shell.h"
#include "wayland_xdg_decoration.h"
#include "wayland_text_input.h"
#include "_cgo_export.h"

@@ -29,6 +30,10 @@ const struct xdg_toplevel_listener gio_xdg_toplevel_listener = {
	.close = gio_onToplevelClose,
};

const struct zxdg_toplevel_decoration_v1_listener gio_zxdg_toplevel_decoration_v1_listener = {
	.configure = gio_onToplevelDecorationConfigure,
};

static void xdg_wm_base_handle_ping(void *data, struct xdg_wm_base *wm, uint32_t serial) {
	xdg_wm_base_pong(wm, serial);
}
diff --git a/app/os_wayland.go b/app/os_wayland.go
index d958b55e..6390d47a 100644
--- a/app/os_wayland.go
+++ b/app/os_wayland.go
@@ -64,6 +64,7 @@ extern const struct wl_registry_listener gio_registry_listener;
extern const struct wl_surface_listener gio_surface_listener;
extern const struct xdg_surface_listener gio_xdg_surface_listener;
extern const struct xdg_toplevel_listener gio_xdg_toplevel_listener;
extern const struct zxdg_toplevel_decoration_v1_listener gio_zxdg_toplevel_decoration_v1_listener;
extern const struct xdg_wm_base_listener gio_xdg_wm_base_listener;
extern const struct wl_callback_listener gio_callback_listener;
extern const struct wl_output_listener gio_output_listener;
@@ -371,9 +372,8 @@ func (d *wlDisplay) createNativeWindow(options []Option) (*window, error) {
	C.xdg_toplevel_add_listener(w.topLvl, &C.gio_xdg_toplevel_listener, unsafe.Pointer(w.surf))

	if d.decor != nil {
		// Request server side decorations.
		w.decor = C.zxdg_decoration_manager_v1_get_toplevel_decoration(d.decor, w.topLvl)
		C.zxdg_toplevel_decoration_v1_set_mode(w.decor, C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE)
		C.zxdg_toplevel_decoration_v1_add_listener(w.decor, &C.gio_zxdg_toplevel_decoration_v1_listener, unsafe.Pointer(w.surf))
	}
	w.updateOpaqueRegion()
	return w, nil
@@ -504,6 +504,22 @@ func gio_onToplevelConfigure(data unsafe.Pointer, topLvl *C.struct_xdg_toplevel,
	w.needAck = true
}

//export gio_onToplevelDecorationConfigure
func gio_onToplevelDecorationConfigure(data unsafe.Pointer, deco *C.struct_zxdg_toplevel_decoration_v1, mode C.uint32_t) {
	w := callbackLoad(data).(*window)
	decorated := w.config.Decorated
	switch mode {
	case C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
		w.config.Decorated = false
	case C.ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
		w.config.Decorated = true
	}
	if decorated != w.config.Decorated {
		w.w.Event(ConfigEvent{Config: w.config})
	}
	w.needAck = true
}

//export gio_onOutputMode
func gio_onOutputMode(data unsafe.Pointer, output *C.struct_wl_output, flags C.uint32_t, width, height, refresh C.int32_t) {
	if flags&C.WL_OUTPUT_MODE_CURRENT == 0 {
-- 
2.32.0

[PATCH gio 3/3] app: swapped the Wayland and X11 drivers Export this patch

From: Pierre Curto <pierre.curto@gmail.com>

Wayland is now the default driver for UNIX platforms.

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
---
 app/os_unix.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/app/os_unix.go b/app/os_unix.go
index ee831b30..c834b6e1 100644
--- a/app/os_unix.go
+++ b/app/os_unix.go
@@ -29,7 +29,7 @@ var wlDriver, x11Driver windowDriver

func newWindow(window *callbacks, options []Option) error {
	var errFirst error
	for _, d := range []windowDriver{x11Driver, wlDriver} {
	for _, d := range []windowDriver{wlDriver, x11Driver} {
		if d == nil {
			continue
		}
-- 
2.32.0
gio/patches: FAILED in 20m47s

[app: use material.Decorations on undecorated platforms][0] from [~pierrec][1]

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

✗ #680603 FAILED  gio/patches/apple.yml   https://builds.sr.ht/~eliasnaur/job/680603
✓ #680606 SUCCESS gio/patches/openbsd.yml https://builds.sr.ht/~eliasnaur/job/680606
✓ #680605 SUCCESS gio/patches/linux.yml   https://builds.sr.ht/~eliasnaur/job/680605
✓ #680604 SUCCESS gio/patches/freebsd.yml https://builds.sr.ht/~eliasnaur/job/680604