summaryrefslogtreecommitdiff
path: root/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl
diff options
context:
space:
mode:
authorNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
committerNippy <nippy@rp1.hu>2026-05-09 13:33:09 +0200
commita2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5 (patch)
tree1a8769217f84bfe9d6216fafaadaf8cdd876d457 /raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl
parent34b9c34f982b2596cfa9e368a2d7f74e9a17477c (diff)
downloadRaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.tar.gz
RaveOS-PKGBUILD-a2b924d7e9492b978ad6dc33b6c1ffcb304b4bc5.zip
raveos update
Diffstat (limited to 'raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl')
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go138
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go522
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go366
-rw-r--r--raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/types.go176
4 files changed, 0 insertions, 1202 deletions
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go
deleted file mode 100644
index e83cc84..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/handlers.go
+++ /dev/null
@@ -1,138 +0,0 @@
-package dwl
-
-import (
- "encoding/json"
- "fmt"
- "net"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/server/models"
-)
-
-type SuccessResult struct {
- Success bool `json:"success"`
- Message string `json:"message"`
-}
-
-func HandleRequest(conn net.Conn, req models.Request, manager *Manager) {
- if manager == nil {
- models.RespondError(conn, req.ID, "dwl manager not initialized")
- return
- }
-
- switch req.Method {
- case "dwl.getState":
- handleGetState(conn, req, manager)
- case "dwl.setTags":
- handleSetTags(conn, req, manager)
- case "dwl.setClientTags":
- handleSetClientTags(conn, req, manager)
- case "dwl.setLayout":
- handleSetLayout(conn, req, manager)
- case "dwl.subscribe":
- handleSubscribe(conn, req, manager)
- default:
- models.RespondError(conn, req.ID, fmt.Sprintf("unknown method: %s", req.Method))
- }
-}
-
-func handleGetState(conn net.Conn, req models.Request, manager *Manager) {
- state := manager.GetState()
- models.Respond(conn, req.ID, state)
-}
-
-func handleSetTags(conn net.Conn, req models.Request, manager *Manager) {
- output, ok := models.Get[string](req, "output")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'output' parameter")
- return
- }
-
- tagmask, ok := models.Get[float64](req, "tagmask")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'tagmask' parameter")
- return
- }
-
- toggleTagset, ok := models.Get[float64](req, "toggleTagset")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'toggleTagset' parameter")
- return
- }
-
- if err := manager.SetTags(output, uint32(tagmask), uint32(toggleTagset)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "tags set"})
-}
-
-func handleSetClientTags(conn net.Conn, req models.Request, manager *Manager) {
- output, ok := models.Get[string](req, "output")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'output' parameter")
- return
- }
-
- andTags, ok := models.Get[float64](req, "andTags")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'andTags' parameter")
- return
- }
-
- xorTags, ok := models.Get[float64](req, "xorTags")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'xorTags' parameter")
- return
- }
-
- if err := manager.SetClientTags(output, uint32(andTags), uint32(xorTags)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "client tags set"})
-}
-
-func handleSetLayout(conn net.Conn, req models.Request, manager *Manager) {
- output, ok := models.Get[string](req, "output")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'output' parameter")
- return
- }
-
- index, ok := models.Get[float64](req, "index")
- if !ok {
- models.RespondError(conn, req.ID, "missing or invalid 'index' parameter")
- return
- }
-
- if err := manager.SetLayout(output, uint32(index)); err != nil {
- models.RespondError(conn, req.ID, err.Error())
- return
- }
-
- models.Respond(conn, req.ID, SuccessResult{Success: true, Message: "layout set"})
-}
-
-func handleSubscribe(conn net.Conn, req models.Request, manager *Manager) {
- clientID := fmt.Sprintf("client-%p", conn)
- stateChan := manager.Subscribe(clientID)
- defer manager.Unsubscribe(clientID)
-
- initialState := manager.GetState()
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- ID: req.ID,
- Result: &initialState,
- }); err != nil {
- return
- }
-
- for state := range stateChan {
- if err := json.NewEncoder(conn).Encode(models.Response[State]{
- Result: &state,
- }); err != nil {
- return
- }
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go
deleted file mode 100644
index 0d21afa..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager.go
+++ /dev/null
@@ -1,522 +0,0 @@
-package dwl
-
-import (
- "fmt"
- "time"
-
- wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
-
- "github.com/AvengeMedia/DankMaterialShell/core/internal/log"
- "github.com/AvengeMedia/DankMaterialShell/core/internal/proto/dwl_ipc"
-)
-
-func NewManager(display wlclient.WaylandDisplay) (*Manager, error) {
- m := &Manager{
- display: display,
- ctx: display.Context(),
- cmdq: make(chan cmd, 128),
- outputSetupReq: make(chan uint32, 16),
- stopChan: make(chan struct{}),
-
- dirty: make(chan struct{}, 1),
- layouts: make([]string, 0),
- }
-
- if err := m.setupRegistry(); err != nil {
- return nil, err
- }
-
- m.updateState()
-
- m.notifierWg.Add(1)
- go m.notifier()
-
- m.wg.Add(1)
- go m.waylandActor()
-
- return m, nil
-}
-
-func (m *Manager) post(fn func()) {
- select {
- case m.cmdq <- cmd{fn: fn}:
- default:
- log.Warn("DWL actor command queue full, dropping command")
- }
-}
-
-func (m *Manager) waylandActor() {
- defer m.wg.Done()
-
- for {
- select {
- case <-m.stopChan:
- return
- case c := <-m.cmdq:
- c.fn()
- case outputID := <-m.outputSetupReq:
- out, exists := m.outputs.Load(outputID)
- if !exists {
- log.Warnf("DWL: Output %d no longer exists, skipping setup", outputID)
- continue
- }
-
- if out.ipcOutput != nil {
- continue
- }
-
- mgr, ok := m.manager.(*dwl_ipc.ZdwlIpcManagerV2)
- if !ok || mgr == nil {
- log.Errorf("DWL: Manager not available for output %d setup", outputID)
- continue
- }
-
- log.Infof("DWL: Setting up ipcOutput for dynamically added output %d", outputID)
- if err := m.setupOutput(mgr, out.output); err != nil {
- log.Errorf("DWL: Failed to setup output %d: %v", outputID, err)
- } else {
- m.updateState()
- }
- }
- }
-}
-
-func (m *Manager) setupRegistry() error {
- log.Info("DWL: starting registry setup")
-
- registry, err := m.display.GetRegistry()
- if err != nil {
- return fmt.Errorf("failed to get registry: %w", err)
- }
- m.registry = registry
-
- outputs := make([]*wlclient.Output, 0)
- outputRegNames := make(map[uint32]uint32)
- var dwlMgr *dwl_ipc.ZdwlIpcManagerV2
-
- registry.SetGlobalHandler(func(e wlclient.RegistryGlobalEvent) {
- switch e.Interface {
- case dwl_ipc.ZdwlIpcManagerV2InterfaceName:
- log.Infof("DWL: found %s", dwl_ipc.ZdwlIpcManagerV2InterfaceName)
- manager := dwl_ipc.NewZdwlIpcManagerV2(m.ctx)
- version := e.Version
- if version > 2 {
- version = 2
- }
- if err := registry.Bind(e.Name, e.Interface, version, manager); err == nil {
- dwlMgr = manager
- log.Info("DWL: manager bound successfully")
-
- // Set handlers immediately after binding, before roundtrips
- manager.SetTagsHandler(func(e dwl_ipc.ZdwlIpcManagerV2TagsEvent) {
- log.Infof("DWL: Tags count: %d", e.Amount)
- m.tagCount = e.Amount
- m.updateState()
- })
-
- manager.SetLayoutHandler(func(e dwl_ipc.ZdwlIpcManagerV2LayoutEvent) {
- log.Infof("DWL: Layout: %s", e.Name)
- m.layouts = append(m.layouts, e.Name)
- m.updateState()
- })
- } else {
- log.Errorf("DWL: failed to bind manager: %v", err)
- }
- case "wl_output":
- log.Debugf("DWL: found wl_output (name=%d)", e.Name)
- output := wlclient.NewOutput(m.ctx)
-
- outState := &outputState{
- registryName: e.Name,
- output: output,
- tags: make([]TagState, 0),
- }
-
- output.SetNameHandler(func(ev wlclient.OutputNameEvent) {
- log.Debugf("DWL: Output name: %s (registry=%d)", ev.Name, e.Name)
- outState.name = ev.Name
- })
-
- output.SetDescriptionHandler(func(ev wlclient.OutputDescriptionEvent) {
- log.Debugf("DWL: Output description: %s", ev.Description)
- })
-
- version := e.Version
- if version > 4 {
- version = 4
- }
- if err := registry.Bind(e.Name, e.Interface, version, output); err == nil {
- outputID := output.ID()
- outState.id = outputID
- log.Infof("DWL: Bound wl_output id=%d registry_name=%d", outputID, e.Name)
- outputs = append(outputs, output)
- outputRegNames[outputID] = e.Name
-
- m.outputs.Store(outputID, outState)
-
- if m.manager != nil {
- select {
- case m.outputSetupReq <- outputID:
- log.Debugf("DWL: Queued setup for output %d", outputID)
- default:
- log.Warnf("DWL: Setup queue full, output %d will not be initialized", outputID)
- }
- }
- } else {
- log.Errorf("DWL: Failed to bind wl_output: %v", err)
- }
- }
- })
-
- registry.SetGlobalRemoveHandler(func(e wlclient.RegistryGlobalRemoveEvent) {
- m.post(func() {
- var outToRelease *outputState
- m.outputs.Range(func(id uint32, out *outputState) bool {
- if out.registryName == e.Name {
- log.Infof("DWL: Output %d removed", id)
- outToRelease = out
- m.outputs.Delete(id)
- return false
- }
- return true
- })
-
- if outToRelease != nil {
- if ipcOut, ok := outToRelease.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2); ok && ipcOut != nil {
- m.wlMutex.Lock()
- ipcOut.Release()
- m.wlMutex.Unlock()
- log.Debugf("DWL: Released ipcOutput for removed output %d", outToRelease.id)
- }
- m.updateState()
- }
- })
- })
-
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("first roundtrip failed: %w", err)
- }
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("second roundtrip failed: %w", err)
- }
-
- if dwlMgr == nil {
- log.Info("DWL: manager not found in registry")
- return fmt.Errorf("dwl_ipc_manager_v2 not available")
- }
-
- m.manager = dwlMgr
-
- for _, output := range outputs {
- if err := m.setupOutput(dwlMgr, output); err != nil {
- log.Warnf("DWL: Failed to setup output %d: %v", output.ID(), err)
- }
- }
-
- if err := m.display.Roundtrip(); err != nil {
- return fmt.Errorf("final roundtrip failed: %w", err)
- }
-
- log.Info("DWL: registry setup complete")
- return nil
-}
-
-func (m *Manager) setupOutput(manager *dwl_ipc.ZdwlIpcManagerV2, output *wlclient.Output) error {
- m.wlMutex.Lock()
- ipcOutput, err := manager.GetOutput(output)
- m.wlMutex.Unlock()
- if err != nil {
- return fmt.Errorf("failed to get dwl output: %w", err)
- }
-
- outState, exists := m.outputs.Load(output.ID())
- if !exists {
- return fmt.Errorf("output state not found for id %d", output.ID())
- }
- outState.ipcOutput = ipcOutput
-
- ipcOutput.SetActiveHandler(func(e dwl_ipc.ZdwlIpcOutputV2ActiveEvent) {
- outState.active = e.Active
- })
-
- ipcOutput.SetTagHandler(func(e dwl_ipc.ZdwlIpcOutputV2TagEvent) {
- updated := false
- for i, tag := range outState.tags {
- if tag.Tag == e.Tag {
- outState.tags[i] = TagState{
- Tag: e.Tag,
- State: e.State,
- Clients: e.Clients,
- Focused: e.Focused,
- }
- updated = true
- break
- }
- }
-
- if !updated {
- outState.tags = append(outState.tags, TagState{
- Tag: e.Tag,
- State: e.State,
- Clients: e.Clients,
- Focused: e.Focused,
- })
- }
-
- m.updateState()
- })
-
- ipcOutput.SetLayoutHandler(func(e dwl_ipc.ZdwlIpcOutputV2LayoutEvent) {
- outState.layout = e.Layout
- })
-
- ipcOutput.SetTitleHandler(func(e dwl_ipc.ZdwlIpcOutputV2TitleEvent) {
- outState.title = e.Title
- })
-
- ipcOutput.SetAppidHandler(func(e dwl_ipc.ZdwlIpcOutputV2AppidEvent) {
- outState.appID = e.Appid
- })
-
- ipcOutput.SetLayoutSymbolHandler(func(e dwl_ipc.ZdwlIpcOutputV2LayoutSymbolEvent) {
- outState.layoutSymbol = e.Layout
- })
-
- ipcOutput.SetKbLayoutHandler(func(e dwl_ipc.ZdwlIpcOutputV2KbLayoutEvent) {
- outState.kbLayout = e.KbLayout
- })
-
- ipcOutput.SetKeymodeHandler(func(e dwl_ipc.ZdwlIpcOutputV2KeymodeEvent) {
- outState.keymode = e.Keymode
- })
-
- ipcOutput.SetFrameHandler(func(e dwl_ipc.ZdwlIpcOutputV2FrameEvent) {
- m.updateState()
- })
-
- return nil
-}
-
-func (m *Manager) updateState() {
- outputs := make(map[string]*OutputState)
- activeOutput := ""
-
- m.outputs.Range(func(key uint32, out *outputState) bool {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
-
- tagsCopy := make([]TagState, len(out.tags))
- copy(tagsCopy, out.tags)
-
- outputs[name] = &OutputState{
- Name: name,
- Active: out.active,
- Tags: tagsCopy,
- Layout: out.layout,
- LayoutSymbol: out.layoutSymbol,
- Title: out.title,
- AppID: out.appID,
- KbLayout: out.kbLayout,
- Keymode: out.keymode,
- }
-
- if out.active != 0 {
- activeOutput = name
- }
- return true
- })
-
- newState := State{
- Outputs: outputs,
- TagCount: m.tagCount,
- Layouts: m.layouts,
- ActiveOutput: activeOutput,
- }
-
- m.stateMutex.Lock()
- m.state = &newState
- m.stateMutex.Unlock()
-
- m.notifySubscribers()
-}
-
-func (m *Manager) notifier() {
- defer m.notifierWg.Done()
- const minGap = 100 * time.Millisecond
- timer := time.NewTimer(minGap)
- timer.Stop()
- var pending bool
-
- for {
- select {
- case <-m.stopChan:
- timer.Stop()
- return
- case <-m.dirty:
- if pending {
- continue
- }
- pending = true
- timer.Reset(minGap)
- case <-timer.C:
- if !pending {
- continue
- }
-
- currentState := m.GetState()
-
- if m.lastNotified != nil && !stateChanged(m.lastNotified, &currentState) {
- pending = false
- continue
- }
-
- m.subscribers.Range(func(key string, ch chan State) bool {
- select {
- case ch <- currentState:
- default:
- log.Warn("DWL: subscriber channel full, dropping update")
- }
- return true
- })
-
- stateCopy := currentState
- m.lastNotified = &stateCopy
- pending = false
- }
- }
-}
-
-func (m *Manager) ensureOutputSetup(out *outputState) error {
- if out.ipcOutput != nil {
- return nil
- }
-
- return fmt.Errorf("output not yet initialized - setup in progress, retry in a moment")
-}
-
-func (m *Manager) SetTags(outputName string, tagmask uint32, toggleTagset uint32) error {
- availableOutputs := make([]string, 0)
- var targetOut *outputState
- m.outputs.Range(func(key uint32, out *outputState) bool {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
- availableOutputs = append(availableOutputs, name)
- if name == outputName {
- targetOut = out
- return false
- }
- return true
- })
-
- if targetOut == nil {
- return fmt.Errorf("output not found: %s (available: %v)", outputName, availableOutputs)
- }
-
- if err := m.ensureOutputSetup(targetOut); err != nil {
- return fmt.Errorf("failed to setup output %s: %w", outputName, err)
- }
-
- ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2)
- if !ok {
- return fmt.Errorf("output %s has invalid ipcOutput type", outputName)
- }
-
- m.wlMutex.Lock()
- err := ipcOut.SetTags(tagmask, toggleTagset)
- m.wlMutex.Unlock()
- return err
-}
-
-func (m *Manager) SetClientTags(outputName string, andTags uint32, xorTags uint32) error {
- var targetOut *outputState
- m.outputs.Range(func(key uint32, out *outputState) bool {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
- if name == outputName {
- targetOut = out
- return false
- }
- return true
- })
-
- if targetOut == nil {
- return fmt.Errorf("output not found: %s", outputName)
- }
-
- if err := m.ensureOutputSetup(targetOut); err != nil {
- return fmt.Errorf("failed to setup output %s: %w", outputName, err)
- }
-
- ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2)
- if !ok {
- return fmt.Errorf("output %s has invalid ipcOutput type", outputName)
- }
-
- m.wlMutex.Lock()
- err := ipcOut.SetClientTags(andTags, xorTags)
- m.wlMutex.Unlock()
- return err
-}
-
-func (m *Manager) SetLayout(outputName string, index uint32) error {
- var targetOut *outputState
- m.outputs.Range(func(key uint32, out *outputState) bool {
- name := out.name
- if name == "" {
- name = fmt.Sprintf("output-%d", out.id)
- }
- if name == outputName {
- targetOut = out
- return false
- }
- return true
- })
-
- if targetOut == nil {
- return fmt.Errorf("output not found: %s", outputName)
- }
-
- if err := m.ensureOutputSetup(targetOut); err != nil {
- return fmt.Errorf("failed to setup output %s: %w", outputName, err)
- }
-
- ipcOut, ok := targetOut.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2)
- if !ok {
- return fmt.Errorf("output %s has invalid ipcOutput type", outputName)
- }
-
- m.wlMutex.Lock()
- err := ipcOut.SetLayout(index)
- m.wlMutex.Unlock()
- return err
-}
-
-func (m *Manager) Close() {
- close(m.stopChan)
- m.wg.Wait()
- m.notifierWg.Wait()
-
- m.subscribers.Range(func(key string, ch chan State) bool {
- close(ch)
- m.subscribers.Delete(key)
- return true
- })
-
- m.outputs.Range(func(key uint32, out *outputState) bool {
- if ipcOut, ok := out.ipcOutput.(*dwl_ipc.ZdwlIpcOutputV2); ok {
- ipcOut.Release()
- }
- m.outputs.Delete(key)
- return true
- })
-
- if mgr, ok := m.manager.(*dwl_ipc.ZdwlIpcManagerV2); ok {
- mgr.Release()
- }
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go
deleted file mode 100644
index 13af137..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/manager_test.go
+++ /dev/null
@@ -1,366 +0,0 @@
-package dwl
-
-import (
- "errors"
- "sync"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-
- mocks_wlclient "github.com/AvengeMedia/DankMaterialShell/core/internal/mocks/wlclient"
-)
-
-func TestStateChanged_BothNil(t *testing.T) {
- assert.True(t, stateChanged(nil, nil))
-}
-
-func TestStateChanged_OneNil(t *testing.T) {
- s := &State{TagCount: 9}
- assert.True(t, stateChanged(s, nil))
- assert.True(t, stateChanged(nil, s))
-}
-
-func TestStateChanged_TagCountDiffers(t *testing.T) {
- a := &State{TagCount: 9, Outputs: make(map[string]*OutputState), Layouts: []string{}}
- b := &State{TagCount: 10, Outputs: make(map[string]*OutputState), Layouts: []string{}}
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_LayoutLengthDiffers(t *testing.T) {
- a := &State{TagCount: 9, Layouts: []string{"tile"}, Outputs: make(map[string]*OutputState)}
- b := &State{TagCount: 9, Layouts: []string{"tile", "monocle"}, Outputs: make(map[string]*OutputState)}
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_ActiveOutputDiffers(t *testing.T) {
- a := &State{TagCount: 9, ActiveOutput: "eDP-1", Outputs: make(map[string]*OutputState), Layouts: []string{}}
- b := &State{TagCount: 9, ActiveOutput: "HDMI-A-1", Outputs: make(map[string]*OutputState), Layouts: []string{}}
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_OutputCountDiffers(t *testing.T) {
- a := &State{
- TagCount: 9,
- Outputs: map[string]*OutputState{"eDP-1": {}},
- Layouts: []string{},
- }
- b := &State{
- TagCount: 9,
- Outputs: map[string]*OutputState{},
- Layouts: []string{},
- }
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_OutputFieldsDiffer(t *testing.T) {
- a := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Active: 1, Layout: 0, Title: "Firefox"},
- },
- }
- b := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Active: 0, Layout: 0, Title: "Firefox"},
- },
- }
- assert.True(t, stateChanged(a, b))
-
- b.Outputs["eDP-1"].Active = 1
- b.Outputs["eDP-1"].Layout = 1
- assert.True(t, stateChanged(a, b))
-
- b.Outputs["eDP-1"].Layout = 0
- b.Outputs["eDP-1"].Title = "Code"
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_TagsDiffer(t *testing.T) {
- a := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Tags: []TagState{{Tag: 1, State: 1, Clients: 2, Focused: 1}}},
- },
- }
- b := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Tags: []TagState{{Tag: 1, State: 2, Clients: 2, Focused: 1}}},
- },
- }
- assert.True(t, stateChanged(a, b))
-
- b.Outputs["eDP-1"].Tags[0].State = 1
- b.Outputs["eDP-1"].Tags[0].Clients = 3
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_Equal(t *testing.T) {
- a := &State{
- TagCount: 9,
- ActiveOutput: "eDP-1",
- Layouts: []string{"tile", "monocle"},
- Outputs: map[string]*OutputState{
- "eDP-1": {
- Name: "eDP-1",
- Active: 1,
- Layout: 0,
- LayoutSymbol: "[]=",
- Title: "Firefox",
- AppID: "firefox",
- KbLayout: "us",
- Keymode: "",
- Tags: []TagState{{Tag: 1, State: 1, Clients: 2, Focused: 1}},
- },
- },
- }
- b := &State{
- TagCount: 9,
- ActiveOutput: "eDP-1",
- Layouts: []string{"tile", "monocle"},
- Outputs: map[string]*OutputState{
- "eDP-1": {
- Name: "eDP-1",
- Active: 1,
- Layout: 0,
- LayoutSymbol: "[]=",
- Title: "Firefox",
- AppID: "firefox",
- KbLayout: "us",
- Keymode: "",
- Tags: []TagState{{Tag: 1, State: 1, Clients: 2, Focused: 1}},
- },
- },
- }
- assert.False(t, stateChanged(a, b))
-}
-
-func TestManager_ConcurrentGetState(t *testing.T) {
- m := &Manager{
- state: &State{
- TagCount: 9,
- Layouts: []string{"tile"},
- Outputs: map[string]*OutputState{"eDP-1": {Name: "eDP-1"}},
- },
- }
-
- var wg sync.WaitGroup
- const goroutines = 50
- const iterations = 100
-
- for i := 0; i < goroutines/2; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for j := 0; j < iterations; j++ {
- s := m.GetState()
- _ = s.TagCount
- _ = s.Outputs
- }
- }()
- }
-
- for i := 0; i < goroutines/2; i++ {
- wg.Add(1)
- go func(i int) {
- defer wg.Done()
- for j := 0; j < iterations; j++ {
- m.stateMutex.Lock()
- m.state = &State{
- TagCount: uint32(j % 10),
- Layouts: []string{"tile", "monocle"},
- Outputs: map[string]*OutputState{"eDP-1": {Active: uint32(j % 2)}},
- }
- m.stateMutex.Unlock()
- }
- }(i)
- }
-
- wg.Wait()
-}
-
-func TestManager_ConcurrentSubscriberAccess(t *testing.T) {
- m := &Manager{
- stopChan: make(chan struct{}),
- dirty: make(chan struct{}, 1),
- }
-
- var wg sync.WaitGroup
- const goroutines = 20
-
- for i := 0; i < goroutines; i++ {
- wg.Add(1)
- go func(id int) {
- defer wg.Done()
- subID := string(rune('a' + id))
- ch := m.Subscribe(subID)
- assert.NotNil(t, ch)
- time.Sleep(time.Millisecond)
- m.Unsubscribe(subID)
- }(i)
- }
-
- wg.Wait()
-}
-
-func TestManager_SyncmapOutputsConcurrentAccess(t *testing.T) {
- m := &Manager{}
-
- var wg sync.WaitGroup
- const goroutines = 30
- const iterations = 50
-
- for i := 0; i < goroutines; i++ {
- wg.Add(1)
- go func(id int) {
- defer wg.Done()
- key := uint32(id)
-
- for j := 0; j < iterations; j++ {
- state := &outputState{
- id: key,
- name: "test-output",
- active: uint32(j % 2),
- tags: []TagState{{Tag: uint32(j), State: 1}},
- }
- m.outputs.Store(key, state)
-
- if loaded, ok := m.outputs.Load(key); ok {
- assert.Equal(t, key, loaded.id)
- }
-
- m.outputs.Range(func(k uint32, v *outputState) bool {
- _ = v.name
- _ = v.active
- return true
- })
- }
-
- m.outputs.Delete(key)
- }(i)
- }
-
- wg.Wait()
-}
-
-func TestManager_NotifySubscribersNonBlocking(t *testing.T) {
- m := &Manager{
- dirty: make(chan struct{}, 1),
- }
-
- for i := 0; i < 10; i++ {
- m.notifySubscribers()
- }
-
- assert.Len(t, m.dirty, 1)
-}
-
-func TestManager_PostQueueFull(t *testing.T) {
- m := &Manager{
- cmdq: make(chan cmd, 2),
- stopChan: make(chan struct{}),
- }
-
- m.post(func() {})
- m.post(func() {})
- m.post(func() {})
- m.post(func() {})
-
- assert.Len(t, m.cmdq, 2)
-}
-
-func TestManager_GetStateNilState(t *testing.T) {
- m := &Manager{}
-
- s := m.GetState()
- assert.NotNil(t, s.Outputs)
- assert.NotNil(t, s.Layouts)
- assert.Equal(t, uint32(0), s.TagCount)
-}
-
-func TestTagState_Fields(t *testing.T) {
- tag := TagState{
- Tag: 1,
- State: 2,
- Clients: 3,
- Focused: 1,
- }
-
- assert.Equal(t, uint32(1), tag.Tag)
- assert.Equal(t, uint32(2), tag.State)
- assert.Equal(t, uint32(3), tag.Clients)
- assert.Equal(t, uint32(1), tag.Focused)
-}
-
-func TestOutputState_Fields(t *testing.T) {
- out := OutputState{
- Name: "eDP-1",
- Active: 1,
- Tags: []TagState{{Tag: 1}},
- Layout: 0,
- LayoutSymbol: "[]=",
- Title: "Firefox",
- AppID: "firefox",
- KbLayout: "us",
- Keymode: "",
- }
-
- assert.Equal(t, "eDP-1", out.Name)
- assert.Equal(t, uint32(1), out.Active)
- assert.Len(t, out.Tags, 1)
- assert.Equal(t, "[]=", out.LayoutSymbol)
-}
-
-func TestStateChanged_NewOutputAppears(t *testing.T) {
- a := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Name: "eDP-1"},
- },
- }
- b := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Name: "eDP-1"},
- "HDMI-A-1": {Name: "HDMI-A-1"},
- },
- }
- assert.True(t, stateChanged(a, b))
-}
-
-func TestStateChanged_TagsLengthDiffers(t *testing.T) {
- a := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Tags: []TagState{{Tag: 1}}},
- },
- }
- b := &State{
- TagCount: 9,
- Layouts: []string{},
- Outputs: map[string]*OutputState{
- "eDP-1": {Tags: []TagState{{Tag: 1}, {Tag: 2}}},
- },
- }
- assert.True(t, stateChanged(a, b))
-}
-
-func TestNewManager_GetRegistryError(t *testing.T) {
- mockDisplay := mocks_wlclient.NewMockWaylandDisplay(t)
-
- mockDisplay.EXPECT().Context().Return(nil)
- mockDisplay.EXPECT().GetRegistry().Return(nil, errors.New("failed to get registry"))
-
- _, err := NewManager(mockDisplay)
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "failed to get registry")
-}
diff --git a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/types.go b/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/types.go
deleted file mode 100644
index 2b17537..0000000
--- a/raveos-hyprland-theme/theme-data/DankMaterialShell/core/internal/server/dwl/types.go
+++ /dev/null
@@ -1,176 +0,0 @@
-package dwl
-
-import (
- "sync"
-
- wlclient "github.com/AvengeMedia/DankMaterialShell/core/pkg/go-wayland/wayland/client"
- "github.com/AvengeMedia/DankMaterialShell/core/pkg/syncmap"
-)
-
-type TagState struct {
- Tag uint32 `json:"tag"`
- State uint32 `json:"state"`
- Clients uint32 `json:"clients"`
- Focused uint32 `json:"focused"`
-}
-
-type OutputState struct {
- Name string `json:"name"`
- Active uint32 `json:"active"`
- Tags []TagState `json:"tags"`
- Layout uint32 `json:"layout"`
- LayoutSymbol string `json:"layoutSymbol"`
- Title string `json:"title"`
- AppID string `json:"appId"`
- KbLayout string `json:"kbLayout"`
- Keymode string `json:"keymode"`
-}
-
-type State struct {
- Outputs map[string]*OutputState `json:"outputs"`
- TagCount uint32 `json:"tagCount"`
- Layouts []string `json:"layouts"`
- ActiveOutput string `json:"activeOutput"`
-}
-
-type cmd struct {
- fn func()
-}
-
-type Manager struct {
- display wlclient.WaylandDisplay
- ctx *wlclient.Context
- registry *wlclient.Registry
- manager any
-
- outputs syncmap.Map[uint32, *outputState]
-
- tagCount uint32
- layouts []string
-
- wlMutex sync.Mutex
- cmdq chan cmd
- outputSetupReq chan uint32
- stopChan chan struct{}
- wg sync.WaitGroup
-
- subscribers syncmap.Map[string, chan State]
- dirty chan struct{}
- notifierWg sync.WaitGroup
- lastNotified *State
-
- stateMutex sync.RWMutex
- state *State
-}
-
-type outputState struct {
- id uint32
- registryName uint32
- output *wlclient.Output
- ipcOutput any
- name string
- active uint32
- tags []TagState
- layout uint32
- layoutSymbol string
- title string
- appID string
- kbLayout string
- keymode string
-}
-
-func (m *Manager) GetState() State {
- m.stateMutex.RLock()
- defer m.stateMutex.RUnlock()
- if m.state == nil {
- return State{
- Outputs: make(map[string]*OutputState),
- Layouts: []string{},
- TagCount: 0,
- }
- }
- stateCopy := *m.state
- return stateCopy
-}
-
-func (m *Manager) Subscribe(id string) chan State {
- ch := make(chan State, 64)
-
- m.subscribers.Store(id, ch)
-
- return ch
-}
-
-func (m *Manager) Unsubscribe(id string) {
- if val, ok := m.subscribers.LoadAndDelete(id); ok {
- close(val)
- }
-}
-
-func (m *Manager) notifySubscribers() {
- select {
- case m.dirty <- struct{}{}:
- default:
- }
-}
-
-func stateChanged(old, new *State) bool {
- if old == nil || new == nil {
- return true
- }
- if old.TagCount != new.TagCount {
- return true
- }
- if len(old.Layouts) != len(new.Layouts) {
- return true
- }
- if old.ActiveOutput != new.ActiveOutput {
- return true
- }
- if len(old.Outputs) != len(new.Outputs) {
- return true
- }
-
- for name, newOut := range new.Outputs {
- oldOut, exists := old.Outputs[name]
- if !exists {
- return true
- }
- if oldOut.Active != newOut.Active {
- return true
- }
- if oldOut.Layout != newOut.Layout {
- return true
- }
- if oldOut.LayoutSymbol != newOut.LayoutSymbol {
- return true
- }
- if oldOut.Title != newOut.Title {
- return true
- }
- if oldOut.AppID != newOut.AppID {
- return true
- }
- if oldOut.KbLayout != newOut.KbLayout {
- return true
- }
- if oldOut.Keymode != newOut.Keymode {
- return true
- }
- if len(oldOut.Tags) != len(newOut.Tags) {
- return true
- }
- for i, newTag := range newOut.Tags {
- if i >= len(oldOut.Tags) {
- return true
- }
- oldTag := oldOut.Tags[i]
- if oldTag.Tag != newTag.Tag || oldTag.State != newTag.State ||
- oldTag.Clients != newTag.Clients || oldTag.Focused != newTag.Focused {
- return true
- }
- }
- }
-
- return false
-}