From 4b88a1d9047e9b5b3b0fed5206d5ba962a765ceb Mon Sep 17 00:00:00 2001 From: defektive Date: Thu, 18 Nov 2021 04:10:41 -0700 Subject: [PATCH] BSPWM Support --- bar/bar.go | 3 + lib/bspwm/bspwm.go | 86 ++++++++++++++++++++++++ ui/module/workspaces.go | 141 ++++++++++++++++++++++++++++++---------- 3 files changed, 194 insertions(+), 36 deletions(-) create mode 100644 lib/bspwm/bspwm.go diff --git a/bar/bar.go b/bar/bar.go index 0b9582d..9334952 100644 --- a/bar/bar.go +++ b/bar/bar.go @@ -69,6 +69,9 @@ func NewBar( return nil, fmt.Errorf("x create: %w", err) } + // Dont show over full screen apps + win.Stack(xproto.StackModeBelow) + // Make this window close gracefully. win.WMGracefulClose(func(w *xwindow.Window) { xevent.Detach(w.X, w.Id) diff --git a/lib/bspwm/bspwm.go b/lib/bspwm/bspwm.go new file mode 100644 index 0000000..58063ab --- /dev/null +++ b/lib/bspwm/bspwm.go @@ -0,0 +1,86 @@ +package bspwm + +import ( + "bufio" + "os/exec" + "regexp" +) + +type Desktop struct { + Num int64 `json:"num"` + Name string `json:"name"` + Visible bool `json:"visible"` + Focused bool `json:"focused"` + Urgent bool `json:"urgent"` + Monitor string `json:"monitor"` +} + +//type Monitor struct { +// Desktops []Desktop `json:"desktops"` +//} + +type BSPWM struct { + //Monitors []Monitor `json:monitors` + desktops []Desktop + notify func(b BSPWM) +} + + +var desktops []Desktop + +func New(notify func(b BSPWM)) *BSPWM { + b := &BSPWM{ + notify: notify, + } + + go b.subscribe() + return b +} + +func (b *BSPWM) subscribe() { + montiorRegExp := regexp.MustCompile(`(^W|:)[Mm][^L]+`) + displayNameRegExp := regexp.MustCompile(`^(W|:)[Mm][^:]+`) + desktopRegExp := regexp.MustCompile(`[oOuUfF][^:]+`) + + cmd := exec.Command("bspc", "subscribe", "report") + stdout, _ := cmd.StdoutPipe() + cmd.Start() + + scanner := bufio.NewScanner(stdout) + scanner.Split(bufio.ScanLines) + for scanner.Scan() { + var desktops []Desktop + bspcStatus := scanner.Text() + monitors := montiorRegExp.FindAllString(bspcStatus, -1) + for _,monitor := range monitors { + + desktopMatches := desktopRegExp.FindAllString(monitor, -1) + displayName := displayNameRegExp.FindString(monitor)[2:] + + for _,bwk := range desktopMatches { + name := bwk[1] + status := bwk[0] + + desktops = append(desktops, Desktop{ + int64(name), + string(name), + true, + status == 'O' || status == 'F', + status == 'O' || status == 'F', + displayName, + }) + } + } + b.setDesktops(desktops) + } + cmd.Wait() +} + +func (b *BSPWM) setDesktops(dsks []Desktop) { + desktops = dsks + b.notify(*b) +} + +func GetDesktops() []Desktop { + return desktops +} \ No newline at end of file diff --git a/ui/module/workspaces.go b/ui/module/workspaces.go index 5da5f59..f546660 100644 --- a/ui/module/workspaces.go +++ b/ui/module/workspaces.go @@ -2,15 +2,28 @@ package module import ( "fmt" + "github.com/shimmerglass/bar3x/lib/bspwm" + log "github.com/sirupsen/logrus" "sort" "github.com/shimmerglass/bar3x/ui" "github.com/shimmerglass/bar3x/ui/base" "github.com/shimmerglass/bar3x/ui/markup" - log "github.com/sirupsen/logrus" "go.i3wm.org/i3/v4" ) +const WM_I3 = "i3" +const WM_BSPWM = "bspwm" + +type workspace struct { + Num int64 `json:"num"` + Name string `json:"name"` + Visible bool `json:"visible"` + Focused bool `json:"focused"` + Urgent bool `json:"urgent"` + Display string `json:"display"` +} + type workspaceIndicator struct { Root *base.Sizer Rect *base.Rect @@ -24,11 +37,13 @@ type Workspaces struct { mk *markup.Markup display string + wm string maxWidth int onlyCurrent bool Row *base.Row els []*workspaceIndicator + workspaces []workspace } func NewWorkspaces(p ui.ParentDrawable, mk *markup.Markup) *Workspaces { @@ -48,32 +63,77 @@ func (m *Workspaces) Init() error { } m.Root = root m.display = m.Context().MustString("display") + //m.update() go func() { - m.update() - er := i3.Subscribe(i3.WorkspaceEventType) - for er.Next() { - m.update() + if m.wm == WM_I3 { + m.i3Update() + + er := i3.Subscribe(i3.WorkspaceEventType) + for er.Next() { + m.i3Update() + } + } else if m.wm == WM_BSPWM { + bspwm.New(func (b bspwm.BSPWM){ + m.bspwmUpdate() + }) } }() return err } -func (m *Workspaces) update() { - wks, err := i3.GetWorkspaces() +func (m *Workspaces) i3Update() { + i3wks, err := i3.GetWorkspaces() if err != nil { log.Errorf("Workspaces: %s", err) return } + wks := []workspace{} + + for _, i3wk := range i3wks { + wks = append(wks, workspace{ + i3wk.Num, + i3wk.Name, + i3wk.Visible, + i3wk.Focused, + i3wk.Urgent, + i3wk.Output, + }) + } + + m.SetWorkspaces(wks) +} +func (m *Workspaces) bspwmUpdate() { + bdsks := bspwm.GetDesktops() + wks := []workspace{} + + for _, bdsk := range bdsks { + wks = append(wks, workspace{ + bdsk.Num, + bdsk.Name, + bdsk.Visible, + bdsk.Focused, + bdsk.Urgent, + bdsk.Monitor, + }) + } + + m.SetWorkspaces(wks) +} + +func (m *Workspaces) SetWorkspaces(wks []workspace) { sort.Slice(wks, func(i, j int) bool { return wks[i].Num < wks[j].Num }) - + m.workspaces = wks + m.update() +} +func (m *Workspaces) update() { j := 0 - for _, wk := range wks { - if wk.Output != m.display { + for _, wk := range m.workspaces { + if wk.Display != m.display { continue } if m.onlyCurrent && !wk.Visible { @@ -88,15 +148,15 @@ func (m *Workspaces) update() { switch { case !wk.Visible && !wk.Focused: - el.Rect.SetColor(m.Context().MustColor("neutral_color")) + el.Rect.SetColor(m.Context().MustColor("bg_color")) el.Text.SetColor(m.Context().MustColor("neutral_light_color")) el.Indicator.SetColor(m.Context().MustColor("neutral_color")) case wk.Visible && !wk.Focused: - el.Rect.SetColor(m.Context().MustColor("neutral_color")) + el.Rect.SetColor(m.Context().MustColor("bg_color")) el.Text.SetColor(m.Context().MustColor("text_color")) el.Indicator.SetColor(m.Context().MustColor("neutral_light_color")) case wk.Visible && wk.Focused: - el.Rect.SetColor(m.Context().MustColor("neutral_color")) + el.Rect.SetColor(m.Context().MustColor("bg_color")) el.Text.SetColor(m.Context().MustColor("text_color")) el.Indicator.SetColor(m.Context().MustColor("accent_color")) } @@ -104,31 +164,33 @@ func (m *Workspaces) update() { el.Text.SetText(wk.Name) el.Root.SetVisible(true) - func(wk i3.Workspace) { - el.Root.SetOnLeftClick(func(ui.Event) bool { - i3.RunCommand(fmt.Sprintf("workspace %s", wk.Name)) - return false - }) - - el.Root.SetOnPointerEnter(func(ui.Event) bool { - el.Indicator.SetColor(m.Context().MustColor("accent_color")) - el.Indicator.Notify() - return true - }) + if m.wm == WM_I3 { + func(wk workspace) { + el.Root.SetOnLeftClick(func(ui.Event) bool { + i3.RunCommand(fmt.Sprintf("workspace %s", wk.Name)) + return false + }) - el.Root.SetOnPointerLeave(func(ui.Event) bool { - switch { - case wk.Focused: + el.Root.SetOnPointerEnter(func(ui.Event) bool { el.Indicator.SetColor(m.Context().MustColor("accent_color")) - case wk.Visible: - el.Indicator.SetColor(m.Context().MustColor("neutral_light_color")) - default: - el.Indicator.SetColor(m.Context().MustColor("neutral_color")) - } - el.Indicator.Notify() - return true - }) - }(wk) + el.Indicator.Notify() + return true + }) + + el.Root.SetOnPointerLeave(func(ui.Event) bool { + switch { + case wk.Focused: + el.Indicator.SetColor(m.Context().MustColor("accent_color")) + case wk.Visible: + el.Indicator.SetColor(m.Context().MustColor("neutral_light_color")) + default: + el.Indicator.SetColor(m.Context().MustColor("neutral_color")) + } + el.Indicator.Notify() + return true + }) + }(wk) + } j++ } @@ -182,6 +244,13 @@ func (m *Workspaces) SetMaxWidth(v int) { m.maxWidth = v } +func (m *Workspaces) WM() string { + return m.wm +} +func (m *Workspaces) SetWM(v string) { + m.wm = v +} + func (m *Workspaces) OnlyCurrent() bool { return m.onlyCurrent }