diff options
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext')
2 files changed, 0 insertions, 328 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go deleted file mode 100644 index 9bbb30a..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext/context.go +++ /dev/null @@ -1,200 +0,0 @@ -package wlcontext - -import ( - "fmt" - "golang.org/x/sys/unix" - "os" - "sync" - "time" - - "github.com/AvengeMedia/DankMaterialShell/core/internal/errdefs" - "github.com/AvengeMedia/DankMaterialShell/core/internal/log" - wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client" -) - -type WaylandContext interface { - Display() *wlclient.Display - Post(fn func()) - FatalError() <-chan error - Start() - Close() -} - -var _ WaylandContext = (*SharedContext)(nil) - -type SharedContext struct { - display *wlclient.Display - stopChan chan struct{} - fatalError chan error - cmdQueue chan func() - wakeR int - wakeW int - wg sync.WaitGroup - mu sync.Mutex - started bool -} - -func New() (*SharedContext, error) { - display, err := wlclient.Connect("") - if err != nil { - return nil, fmt.Errorf("%w: %v", errdefs.ErrNoWaylandDisplay, err) - } - - fds := make([]int, 2) - if err := unix.Pipe(fds); err != nil { - display.Context().Close() - return nil, fmt.Errorf("failed to create wake pipe: %w", err) - } - if err := unix.SetNonblock(fds[0], true); err != nil { - unix.Close(fds[0]) - unix.Close(fds[1]) - display.Context().Close() - return nil, fmt.Errorf("failed to set wake pipe nonblock: %w", err) - } - if err := unix.SetNonblock(fds[1], true); err != nil { - unix.Close(fds[0]) - unix.Close(fds[1]) - display.Context().Close() - return nil, fmt.Errorf("failed to set wake pipe nonblock: %w", err) - } - - sc := &SharedContext{ - display: display, - stopChan: make(chan struct{}), - fatalError: make(chan error, 1), - cmdQueue: make(chan func(), 256), - wakeR: fds[0], - wakeW: fds[1], - started: false, - } - - return sc, nil -} - -func (sc *SharedContext) Start() { - sc.mu.Lock() - defer sc.mu.Unlock() - - if sc.started { - return - } - - sc.started = true - sc.wg.Add(1) - go sc.eventDispatcher() -} - -func (sc *SharedContext) Display() *wlclient.Display { - return sc.display -} - -func (sc *SharedContext) Post(fn func()) { - select { - case sc.cmdQueue <- fn: - if _, err := unix.Write(sc.wakeW, []byte{1}); err != nil && err != unix.EAGAIN { - log.Errorf("wake pipe write error: %v", err) - } - default: - } -} - -func (sc *SharedContext) FatalError() <-chan error { - return sc.fatalError -} - -func (sc *SharedContext) eventDispatcher() { - defer sc.wg.Done() - defer func() { - if r := recover(); r != nil { - err := fmt.Errorf("FATAL: Wayland event dispatcher panic: %v", r) - log.Error(err) - select { - case sc.fatalError <- err: - default: - } - } - }() - - ctx := sc.display.Context() - wlFd := ctx.Fd() - - pollFds := []unix.PollFd{ - {Fd: int32(wlFd), Events: unix.POLLIN}, - {Fd: int32(sc.wakeR), Events: unix.POLLIN}, - } - - consecutiveErrors := 0 - const maxConsecutiveErrors = 20 - - for { - sc.drainCmdQueue() - - select { - case <-sc.stopChan: - return - default: - } - - _, err := unix.Poll(pollFds, -1) - switch { - case err == unix.EINTR: - continue - case err != nil: - log.Errorf("Poll error: %v", err) - return - } - - if pollFds[1].Revents&unix.POLLIN != 0 { - var buf [64]byte - if _, err := unix.Read(sc.wakeR, buf[:]); err != nil && err != unix.EAGAIN { - log.Errorf("wake pipe read error: %v", err) - } - } - - if pollFds[0].Revents&unix.POLLIN == 0 { - continue - } - - if err := ctx.Dispatch(); err != nil && !os.IsTimeout(err) { - consecutiveErrors++ - log.Warnf("Wayland connection error (%d/%d): %v", consecutiveErrors, maxConsecutiveErrors, err) - - if consecutiveErrors >= maxConsecutiveErrors { - log.Errorf("Fatal: Wayland connection unrecoverable after %d attempts. Exiting dispatcher.", maxConsecutiveErrors) - return - } - - time.Sleep(100 * time.Millisecond * time.Duration(consecutiveErrors)) - continue - } - - consecutiveErrors = 0 - } -} - -func (sc *SharedContext) drainCmdQueue() { - for { - select { - case fn := <-sc.cmdQueue: - fn() - default: - return - } - } -} - -func (sc *SharedContext) Close() { - close(sc.stopChan) - if _, err := unix.Write(sc.wakeW, []byte{1}); err != nil && err != unix.EAGAIN { - log.Errorf("wake pipe write error on close: %v", err) - } - sc.wg.Wait() - - unix.Close(sc.wakeR) - unix.Close(sc.wakeW) - - if sc.display == nil { - return - } - sc.display.Context().Close() -} diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go deleted file mode 100644 index 11ecfbf..0000000 --- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/wlcontext/context_test.go +++ /dev/null @@ -1,128 +0,0 @@ -package wlcontext - -import ( - "sync" - "testing" - - "github.com/stretchr/testify/assert" - "golang.org/x/sys/unix" -) - -func newTestSharedContext(t *testing.T, queueSize int) *SharedContext { - t.Helper() - fds := make([]int, 2) - if err := unix.Pipe(fds); err != nil { - t.Fatalf("failed to create test pipe: %v", err) - } - t.Cleanup(func() { - unix.Close(fds[0]) - unix.Close(fds[1]) - }) - return &SharedContext{ - cmdQueue: make(chan func(), queueSize), - stopChan: make(chan struct{}), - wakeR: fds[0], - wakeW: fds[1], - } -} - -func TestSharedContext_ConcurrentPostNonBlocking(t *testing.T) { - sc := newTestSharedContext(t, 256) - - var wg sync.WaitGroup - const goroutines = 100 - const iterations = 50 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func(id int) { - defer wg.Done() - for j := 0; j < iterations; j++ { - sc.Post(func() { - _ = id + j - }) - } - }(i) - } - - wg.Wait() -} - -func TestSharedContext_PostQueueFull(t *testing.T) { - sc := newTestSharedContext(t, 2) - - sc.Post(func() {}) - sc.Post(func() {}) - sc.Post(func() {}) - sc.Post(func() {}) - - assert.Len(t, sc.cmdQueue, 2) -} - -func TestSharedContext_StartMultipleTimes(t *testing.T) { - sc := newTestSharedContext(t, 256) - sc.started = true - - var wg sync.WaitGroup - const goroutines = 10 - - for i := 0; i < goroutines; i++ { - wg.Add(1) - go func() { - defer wg.Done() - sc.Start() - }() - } - - wg.Wait() - - assert.True(t, sc.started) -} - -func TestSharedContext_DrainCmdQueue(t *testing.T) { - sc := newTestSharedContext(t, 256) - - counter := 0 - for i := 0; i < 10; i++ { - sc.cmdQueue <- func() { - counter++ - } - } - - sc.drainCmdQueue() - - assert.Equal(t, 10, counter) - assert.Len(t, sc.cmdQueue, 0) -} - -func TestSharedContext_DrainCmdQueueEmpty(t *testing.T) { - sc := newTestSharedContext(t, 256) - - sc.drainCmdQueue() - - assert.Len(t, sc.cmdQueue, 0) -} - -func TestSharedContext_ConcurrentDrainAndPost(t *testing.T) { - sc := newTestSharedContext(t, 256) - - var wg sync.WaitGroup - - wg.Add(1) - go func() { - defer wg.Done() - for i := 0; i < 100; i++ { - sc.Post(func() {}) - } - }() - - wg.Add(1) - go func() { - defer wg.Done() - for i := 0; i < 50; i++ { - sc.drainCmdQueue() - } - }() - - wg.Wait() -} |