mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-15 18:22:08 -04:00
core/wayland: thread-safety meta fixes + cleanups + hypr workaround
- fork go-wayland/client and modify to make it thread-safe internally - use sync.Map and atomic values in many places to cut down on mutex boilerplate - do not create extworkspace client unless explicitly requested
This commit is contained in:
110
core/pkg/go-wayland/wayland/client/context.go
Normal file
110
core/pkg/go-wayland/wayland/client/context.go
Normal file
@@ -0,0 +1,110 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Context struct {
|
||||
conn *net.UnixConn
|
||||
objects sync.Map // map[uint32]Proxy - thread-safe concurrent map
|
||||
currentID uint32
|
||||
idMu sync.Mutex // protects currentID increment
|
||||
}
|
||||
|
||||
func (ctx *Context) Register(p Proxy) {
|
||||
ctx.idMu.Lock()
|
||||
ctx.currentID++
|
||||
id := ctx.currentID
|
||||
ctx.idMu.Unlock()
|
||||
|
||||
p.SetID(id)
|
||||
p.SetContext(ctx)
|
||||
ctx.objects.Store(id, p)
|
||||
}
|
||||
|
||||
func (ctx *Context) Unregister(p Proxy) {
|
||||
ctx.objects.Delete(p.ID())
|
||||
}
|
||||
|
||||
func (ctx *Context) GetProxy(id uint32) Proxy {
|
||||
if val, ok := ctx.objects.Load(id); ok {
|
||||
return val.(Proxy)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctx *Context) Close() error {
|
||||
return ctx.conn.Close()
|
||||
}
|
||||
|
||||
// Dispatch reads and processes incoming messages and calls [client.Dispatcher.Dispatch] on the
|
||||
// respective wayland protocol.
|
||||
// Dispatch must be called on the same goroutine as other interactions with the Context.
|
||||
// If a multi goroutine approach is desired, use [Context.GetDispatch] instead.
|
||||
// Dispatch blocks if there are no incoming messages.
|
||||
// A Dispatch loop is usually used to handle incoming messages.
|
||||
func (ctx *Context) Dispatch() error {
|
||||
return ctx.GetDispatch()()
|
||||
}
|
||||
|
||||
var ErrDispatchSenderNotFound = errors.New("dispatch: unable to find sender")
|
||||
var ErrDispatchSenderUnsupported = errors.New("dispatch: sender does not implement Dispatch method")
|
||||
var ErrDispatchUnableToReadMsg = errors.New("dispatch: unable to read msg")
|
||||
|
||||
// GetDispatch reads incoming messages and returns the dispatch function which calls
|
||||
// [client.Dispatcher.Dispatch] on the respective wayland protocol.
|
||||
// This function is now thread-safe and can be called from multiple goroutines.
|
||||
// GetDispatch blocks if there are no incoming messages.
|
||||
func (ctx *Context) GetDispatch() func() error {
|
||||
senderID, opcode, fd, data, err := ctx.ReadMsg() // Blocks if there are no incoming messages
|
||||
if err != nil {
|
||||
return func() error {
|
||||
return fmt.Errorf("%w: %w", ErrDispatchUnableToReadMsg, err)
|
||||
}
|
||||
}
|
||||
|
||||
return func() error {
|
||||
val, ok := ctx.objects.Load(senderID)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w (senderID=%d)", ErrDispatchSenderNotFound, senderID)
|
||||
}
|
||||
|
||||
sender, ok := val.(Dispatcher)
|
||||
if !ok {
|
||||
return fmt.Errorf("%w (senderID=%d)", ErrDispatchSenderUnsupported, senderID)
|
||||
}
|
||||
|
||||
sender.Dispatch(opcode, fd, data)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func Connect(addr string) (*Display, error) {
|
||||
if addr == "" {
|
||||
runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
|
||||
if runtimeDir == "" {
|
||||
return nil, errors.New("env XDG_RUNTIME_DIR not set")
|
||||
}
|
||||
if addr == "" {
|
||||
addr = os.Getenv("WAYLAND_DISPLAY")
|
||||
}
|
||||
if addr == "" {
|
||||
addr = "wayland-0"
|
||||
}
|
||||
addr = runtimeDir + "/" + addr
|
||||
}
|
||||
|
||||
ctx := &Context{}
|
||||
|
||||
conn, err := net.DialUnix("unix", nil, &net.UnixAddr{Name: addr, Net: "unix"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ctx.conn = conn
|
||||
|
||||
return NewDisplay(ctx), nil
|
||||
}
|
||||
Reference in New Issue
Block a user