From e028a07b72ae60380b50734a3d02e10b8711e928 Mon Sep 17 00:00:00 2001 From: Cosmo Borsky Date: Mon, 21 Jan 2019 15:27:24 -0500 Subject: [PATCH 1/7] Add option to remove desktop after focus change This will allow you to keep an empty desktop open if you're focused in it Set `remove-focused = false` in your config.toml to active this feature --- config/config.go | 2 ++ handlers/handlers.go | 5 +++++ monitors/monitors.go | 1 + 3 files changed, 8 insertions(+) diff --git a/config/config.go b/config/config.go index 3266fe8..34f277f 100644 --- a/config/config.go +++ b/config/config.go @@ -24,6 +24,7 @@ type Config struct { Min int Max int RemoveEmpty bool `mapstructure:"remove-empty"` + RemoveFocused bool `mapstructure:"remove-focused"` AppendWhenOccupied bool `mapstructure:"append-when-occupied"` WatchConfig bool `mapstructure:"watch-config"` configChangeC chan bool @@ -89,6 +90,7 @@ func newDefaultConfig() *viper.Viper { c.SetDefault("min", 1) c.SetDefault("max", math.MaxInt64) c.SetDefault("remove-empty", true) + c.SetDefault("remove-focused", true) c.SetDefault("append-when-occupied", true) c.SetDefault("renamers", []string{numeric}) c.SetDefault("watch-config", true) diff --git a/handlers/handlers.go b/handlers/handlers.go index 41750a4..ee9b635 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -143,6 +143,11 @@ func (r RemoveHandler) Handle(m *monitors.Monitors) bool { continue } + // TODO: Should we handle desktop destruction if the monitor focus is switched? + if !r.config.RemoveFocused && monitor.FocusedDesktopId == desktop.Id { + continue + } + err := monitor.RemoveDesktop(desktop.Id) if err != nil { log.Println("Unable to remove desktop: ", desktop.Name, err) diff --git a/monitors/monitors.go b/monitors/monitors.go index 2c07098..ca3460b 100644 --- a/monitors/monitors.go +++ b/monitors/monitors.go @@ -15,6 +15,7 @@ type bspwmState struct { type Monitor struct { Name string Id int + FocusedDesktopId int Desktops []Desktop } From b48916b74709e0ddaedc628469d96333eaf9bac5 Mon Sep 17 00:00:00 2001 From: Cosmo Borsky Date: Thu, 24 Jan 2019 21:54:41 -0500 Subject: [PATCH 2/7] Add remove-focused to readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a9bf96a..88098e0 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Below are the different configuration options available. Please look at [exampl | min | Int | Minimum number of desktops per monitor | 1 | | max | Int | Maximum number of desktops per monitor | infinity | | remove-empty | Bool | Removes empty desktops | true | +| remove-focused | Bool | Removes focused desktops | false | | append-when-occupied | Bool | Appends a new desktop when all other desktops are occupied | true | | watch-config | Bool | Reload btops on next event when configuration changes | true | | renamers | []String | Order of [renamers](#renamers) to use for renaming desktops. If a given renamer is unable to rename a desktop, it cascades to the next renmaer | ["numeric"] From fea79f4bbdebf5d2a3f0742971d5bbfec5f92f71 Mon Sep 17 00:00:00 2001 From: Cosmo Borsky Date: Thu, 24 Jan 2019 22:04:25 -0500 Subject: [PATCH 3/7] Only remove a desktop if more than one is empty --- handlers/handlers.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index ee9b635..33d74b9 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -134,11 +134,10 @@ func (r RemoveHandler) ShouldHandle() bool { func (r RemoveHandler) Handle(m *monitors.Monitors) bool { for _, monitor := range *m { + if len(monitor.EmptyDesktops()) == 1 { + return true + } for _, desktop := range monitor.EmptyDesktops() { - if *desktop == monitor.Desktops[len(monitor.Desktops)-1] { - continue - } - if r.config.Min >= len(monitor.Desktops) { continue } From aca7eb7576a647385778b85cff40edcba3c6845f Mon Sep 17 00:00:00 2001 From: David Lima Date: Fri, 26 Jan 2024 13:59:01 -0300 Subject: [PATCH 4/7] Remove wrong return statement Return true statement that was stopping other handler to get reached --- go.mod | 26 ++++++++++++++++++++++++++ go.sum | 43 +++++++++++++++++++++++++++++++++++++++++++ handlers/handlers.go | 7 ++++--- 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b4edb59 --- /dev/null +++ b/go.mod @@ -0,0 +1,26 @@ +module github.com/cmschuetz/btops + +go 1.21.6 + +require ( + github.com/fsnotify/fsnotify v1.4.2 + github.com/spf13/viper v1.0.0 +) + +require ( + github.com/BurntSushi/toml v1.3.2 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb // indirect + github.com/magiconair/properties v1.7.3 // indirect + github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e // indirect + github.com/pelletier/go-toml v1.0.1 // indirect + github.com/spf13/afero v1.0.0 // indirect + github.com/spf13/cast v1.1.0 // indirect + github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 // indirect + github.com/spf13/pflag v1.0.0 // indirect + github.com/stretchr/testify v1.8.4 // indirect + golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc // indirect + golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect + gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..fb277e1 --- /dev/null +++ b/go.sum @@ -0,0 +1,43 @@ +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fsnotify/fsnotify v1.4.2 h1:v5tKwtf2hNhBV24eNYfQ5UmvFOGlOCmRqk7/P1olxtk= +github.com/fsnotify/fsnotify v1.4.2/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb h1:1OvvPvZkn/yCQ3xBcM8y4020wdkMXPHLB4+NfoGWh4U= +github.com/hashicorp/hcl v0.0.0-20171017181929-23c074d0eceb/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w= +github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/magiconair/properties v1.7.3 h1:6AOjgCKyZFMG/1yfReDPDz3CJZPxnYk7DGmj2HtyF24= +github.com/magiconair/properties v1.7.3/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e h1:PtGHLB3CX3TFPcksODQMxncoeQKWwCgTg0bJ40VLJP4= +github.com/mitchellh/mapstructure v0.0.0-20171017171808-06020f85339e/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/pelletier/go-toml v1.0.1 h1:0nx4vKBl23+hEaCOV1mFhKS9vhhBtFYWC7rQY0vJAyE= +github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/spf13/afero v1.0.0 h1:Z005C09nPzwTTsDRJCQBVnpTU0bjTr/NhyWLj1nSPP4= +github.com/spf13/afero v1.0.0/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.1.0 h1:0Rhw4d6C8J9VPu6cjZLIhZ8+aAOHcDvGeKn+cq5Aq3k= +github.com/spf13/cast v1.1.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= +github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386 h1:zBoLErXXAvWnNsu+pWkRYl6Cx1KXmIfAVsIuYkPN6aY= +github.com/spf13/jwalterweatherman v0.0.0-20170901151539-12bd96e66386/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.0 h1:oaPbdDe/x0UncahuwiPxW1GYJyilRAdsPnq3e1yaPcI= +github.com/spf13/pflag v1.0.0/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.0.0 h1:RUA/ghS2i64rlnn4ydTfblY8Og8QzcPtCcHvgMn+w/I= +github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc h1:pt5pMsz4A/sZRT17MOvX/nidmCt7n6ILLJBkNh5QqC8= +golang.org/x/sys v0.0.0-20171114162044-bf42f188b9bc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3 h1:OxMYHd6bm+jH+TI7NBCb/CaYk6pMJnBC8GIzIi68Hk4= +golang.org/x/text v0.1.1-0.20171102192421-88f656faf3f3/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab h1:yZ6iByf7GKeJ3gsd1Dr/xaj1DyJ//wxKX1Cdh8LhoAw= +gopkg.in/yaml.v2 v2.0.0-20171116090243-287cf08546ab/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/handlers/handlers.go b/handlers/handlers.go index 33d74b9..3c14958 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -134,9 +134,10 @@ func (r RemoveHandler) ShouldHandle() bool { func (r RemoveHandler) Handle(m *monitors.Monitors) bool { for _, monitor := range *m { - if len(monitor.EmptyDesktops()) == 1 { - return true - } + if len(monitor.EmptyDesktops()) == 1 { + continue + } + for _, desktop := range monitor.EmptyDesktops() { if r.config.Min >= len(monitor.Desktops) { continue From 53a1990b6230ffe1d0d3473737664152dac67a77 Mon Sep 17 00:00:00 2001 From: David Lima Date: Fri, 26 Jan 2024 14:14:12 -0300 Subject: [PATCH 5/7] Prevents empty desktops between occupied desktops that aren't being focused Remove unfocused desktops that aren't in the last position Remove the last desktop if the one before him is empty --- handlers/handlers.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/handlers/handlers.go b/handlers/handlers.go index 3c14958..af85eb1 100644 --- a/handlers/handlers.go +++ b/handlers/handlers.go @@ -143,11 +143,14 @@ func (r RemoveHandler) Handle(m *monitors.Monitors) bool { continue } - // TODO: Should we handle desktop destruction if the monitor focus is switched? if !r.config.RemoveFocused && monitor.FocusedDesktopId == desktop.Id { continue } + if *desktop == monitor.Desktops[len(monitor.Desktops)-1] && !(monitor.Desktops[len(monitor.Desktops)-2].IsEmpty()) { + continue + } + err := monitor.RemoveDesktop(desktop.Id) if err != nil { log.Println("Unable to remove desktop: ", desktop.Name, err) From 60175295e47e0fa4894bd53e0479a7024f79b4ea Mon Sep 17 00:00:00 2001 From: David Lima Date: Fri, 26 Jan 2024 14:15:44 -0300 Subject: [PATCH 6/7] Add binary to .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 46bdf95..f1b3f65 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,6 @@ *.out # Vendor -vendor/ \ No newline at end of file +vendor/ + +btops From 054f1d5e33c88320af775268da9b55da255c8465 Mon Sep 17 00:00:00 2001 From: David Lima Date: Fri, 30 May 2025 08:49:12 -0300 Subject: [PATCH 7/7] Change README so links point to original repo Signed-off-by: David Lima --- README.md | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 88098e0..53f1a10 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,24 @@ bspwm desktop management that supports dymanic appending, removing, and renaming ## Introduction -Often times a workflow for a given day can't be defined by a set number of desktops with constant names. Btops enables you to define your workspaces based on what you're doing so you don't have worry about things like putting your applications in their respective desktops, running out of desktops, or leaving desktops unused and empty. +Often times a workflow for a given day can't be defined by a set number of desktops with constant names. Btops enables you to define your workspaces based on what you're doing so you don't have to worry about things like putting your applications in their respective desktops, running out of desktops, or leaving desktops unused and empty. ## Examples -#### Dynamic with classified renamers -[![btops dynamic](https://thumbs.gfycat.com/CourteousHeavyGibbon-size_restricted.gif)](https://gfycat.com/CourteousHeavyGibbon) - -#### [Minmax](https://github.com/cmschuetz/btops/blob/master/examples/minmax.toml) -[![btops minmax](https://thumbs.gfycat.com/HairyRewardingIncatern-size_restricted.gif)](https://gfycat.com/HairyRewardingIncatern) - +- [Dynamic with classified renamers](https://github.com/cmschuetz/btops/blob/master/examples/classified.toml)Add commentMore actions +- [Minmax with numeric renamer](https://github.com/cmschuetz/btops/blob/master/examples/minmax.toml) +- [Static](https://github.com/cmschuetz/btops/blob/master/examples/static.toml) ## Configuration -btops supports config files in toml, json, and yaml format. It'll look in the following places for config files: +btops supports config files in toml, json, and yaml format. It'll look in the following places for config files: ``` $XDG_CONFIG_HOME/btops/config.* ~/.config/btops/config.* ``` -Below are the different configuration options available. Please look at [examples](https://github.com/cmschuetz/btops/tree/master/examples) for example usage +Below are the different configuration options available. Please look at [examples](https://github.com/cmschuetz/btops/tree/master/examples) for example usage ### Configuration Options @@ -36,7 +33,7 @@ Below are the different configuration options available. Please look at [exampl | remove-focused | Bool | Removes focused desktops | false | | append-when-occupied | Bool | Appends a new desktop when all other desktops are occupied | true | | watch-config | Bool | Reload btops on next event when configuration changes | true | -| renamers | []String | Order of [renamers](#renamers) to use for renaming desktops. If a given renamer is unable to rename a desktop, it cascades to the next renmaer | ["numeric"] +| renamers | []String | Order of [renamers](#renamers) to use for renaming desktops. If a given renamer is unable to rename a desktop, it cascades to the next renmaer | ["numeric"] | | names | Names | [Names configuration object](#names) | {} | ### Renamers @@ -56,12 +53,12 @@ names configuration object | ------ | ---- | ----------- | | constant | String | A single string that the constant renamer uses to rename desktops | | static | []String | A list of desktop names that the static renamer uses to rename desktops | -| classified | []{ classification: []String (clients) } | An array of objects that match client names with a given classification. If multiple classifications are matched, the first will be used as the desktop name +| classified | []{ classification: []String (clients) } | An array of objects that match client names with a given classification. If multiple classifications are matched, the first will be used as the desktop name | ## Installation -- Ensure [go](https://golang.org/) is installed and your [$GOPATH](https://github.com/golang/go/wiki/GOPATH) is set -- `go get github.com/cmschuetz/btops` +- Ensure [Go](https://go.dev/) is installed and your [$GOPATH](https://go.dev/wiki/GOPATH) is set +- `go install github.com/cmschuetz/btops@latest` - run `$GOPATH/bin/btops` ### Arch Linux