Skip to content

Commit

Permalink
feat: remember tiling state and layout proportions #44
Browse files Browse the repository at this point in the history
  • Loading branch information
leukipp committed Feb 29, 2024
1 parent e63b5cf commit 792e864
Show file tree
Hide file tree
Showing 15 changed files with 386 additions and 186 deletions.
8 changes: 4 additions & 4 deletions assets/scripts/listen.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,16 @@ while json=$(nc -Ulw 1 $sockout | jq -r "."); do

case ${type} in
"Action")
desk=$(echo $data | jq -r ".Desk")
screen=$(echo $data | jq -r ".Screen")
desk=$(echo $data | jq -r ".DeskNum")
screen=$(echo $data | jq -r ".ScreenNum")

# EXAMPLE: retrieve action event on active workspace
echo "Received 'action' with name '$name' on 'desktop = $desk' and 'screen = $screen'";;
"State")
case ${name} in
"workspaces")
desk=$(echo $data | jq -r ".Desk")
screen=$(echo $data | jq -r ".Screen")
desk=$(echo $data | jq -r ".DeskNum")
screen=$(echo $data | jq -r ".ScreenNum")
workspace=$(echo $data | jq -r ".Workspaces[] | select((.Location.DeskNum==$desk) and (.Location.ScreenNum==$screen))")
enabled=$(echo $workspace | jq -r ".TilingEnabled")
layout=$(echo $workspace | jq -r ".ActiveLayoutNum")
Expand Down
10 changes: 8 additions & 2 deletions common/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"os"
"strings"

"path/filepath"

Expand All @@ -15,14 +16,14 @@ type Cache[T any] struct {
}

func InitCache() {
if Args.Cache == "0" {
if !CacheEnabled() {
return
}

// Create cache folder if not exists
cacheFolderPath := Args.Cache
if _, err := os.Stat(cacheFolderPath); os.IsNotExist(err) {
os.MkdirAll(cacheFolderPath, 0700)
os.MkdirAll(cacheFolderPath, 0755)
}
}

Expand All @@ -36,3 +37,8 @@ func CacheFolderPath(name string) string {

return filepath.Join(userCacheDir, name)
}

func CacheEnabled() bool {
arg := strings.ToLower(strings.TrimSpace(Args.Cache))
return !IsInList(arg, []string{"", "0", "off", "false", "disabled"})
}
3 changes: 1 addition & 2 deletions common/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ type Configuration struct {
WindowSlavesMax int `toml:"window_slaves_max"` // Maximum number of allowed slaves
WindowGapSize int `toml:"window_gap_size"` // Gap size between windows
WindowDecoration bool `toml:"window_decoration"` // Show window decorations
Proportion float64 `toml:"proportion"` // Master-slave area initial proportion
ProportionStep float64 `toml:"proportion_step"` // Master-slave area step size proportion
ProportionMin float64 `toml:"proportion_min"` // Window size minimum proportion
EdgeMargin []int `toml:"edge_margin"` // Margin values of tiling area
Expand All @@ -44,7 +43,7 @@ func InitConfig() {
// Create config folder if not exists
configFolderPath := filepath.Dir(Args.Config)
if _, err := os.Stat(configFolderPath); os.IsNotExist(err) {
os.MkdirAll(configFolderPath, 0700)
os.MkdirAll(configFolderPath, 0755)
}

// Write default config if not exists
Expand Down
7 changes: 4 additions & 3 deletions config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ tiling_icon = [
["slave_increase", "Add Slave"],
["slave_decrease", "Remove Slave"],
["", ""],
["reset", "Reset"],
["exit", "Exit"],
]

Expand Down Expand Up @@ -63,9 +64,6 @@ window_decoration = true

################################## Proportion ##################################

# Initial division of master-slave area (0.0 - 1.0).
proportion = 0.6

# How much to increment/decrement master-slave area (0.0 - 1.0).
proportion_step = 0.05

Expand Down Expand Up @@ -124,6 +122,9 @@ restore = "Control-Shift-R"
# Toggle between enable and disable on the current screen.
toggle = "Control-Shift-T"

# Reset layouts to default proportions (BackSpace = Delete_Left)
reset = "Control-Shift-BackSpace"

# Cycles through next layouts (Next = Page_Down).
cycle_next = "Control-Shift-Next"

Expand Down
1 change: 1 addition & 0 deletions desktop/layout.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package desktop
import "github.com/leukipp/cortile/v2/store"

type Layout interface {
Reset()
Apply()
AddClient(c *store.Client)
RemoveClient(c *store.Client)
Expand Down
51 changes: 31 additions & 20 deletions desktop/tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ type HandlerClient struct {
Target *store.Client // Stores hovered client
}

func CreateTracker(ws map[store.Location]*Workspace) *Tracker {
func CreateTracker() *Tracker {
tr := Tracker{
Clients: make(map[xproto.Window]*store.Client),
Workspaces: ws,
Workspaces: CreateWorkspaces(),
Action: make(chan string),
Handler: &Handler{
ResizeClient: &HandlerClient{},
Expand All @@ -54,11 +54,6 @@ func CreateTracker(ws map[store.Location]*Workspace) *Tracker {
store.OnStateUpdate(tr.onStateUpdate)
store.OnPointerUpdate(tr.onPointerUpdate)

// Populate clients on startup
if common.Config.TilingEnabled {
tr.Update()
}

return &tr
}

Expand Down Expand Up @@ -102,6 +97,19 @@ func (tr *Tracker) Reset() {
tr.Workspaces = CreateWorkspaces()
}

func (tr *Tracker) Write() {

// Write client cache
for _, c := range tr.Clients {
c.Write()
}

// Write workspace cache
for _, ws := range tr.Workspaces {
ws.Write()
}
}

func (tr *Tracker) ActiveWorkspace() *Workspace {
location := store.Location{DeskNum: store.CurrentDesk, ScreenNum: store.CurrentScreen}

Expand All @@ -126,6 +134,19 @@ func (tr *Tracker) ClientWorkspace(c *store.Client) *Workspace {
return ws
}

func (tr *Tracker) unlockClients() {
ws := tr.ActiveWorkspace()
mg := ws.ActiveLayout().GetManager()

// Unlock clients
for _, c := range mg.Clients(store.Stacked) {
if c == nil {
continue
}
c.UnLock()
}
}

func (tr *Tracker) trackWindow(w xproto.Window) bool {
if tr.isTracked(w) {
return false
Expand Down Expand Up @@ -391,19 +412,6 @@ func (tr *Tracker) handleWorkspaceChange(c *store.Client) {
tr.Handler.SwapScreen.Active = false
}

func (tr *Tracker) unlockClients() {
ws := tr.ActiveWorkspace()
mg := ws.ActiveLayout().GetManager()

// Unlock clients
for _, c := range mg.Clients(store.Stacked) {
if c == nil {
continue
}
c.UnLock()
}
}

func (tr *Tracker) onStateUpdate(aname string) {
viewportChanged := common.IsInList(aname, []string{"_NET_NUMBER_OF_DESKTOPS", "_NET_DESKTOP_LAYOUT", "_NET_DESKTOP_GEOMETRY", "_NET_DESKTOP_VIEWPORT", "_NET_WORKAREA"})
clientsChanged := common.IsInList(aname, []string{"_NET_CLIENT_LIST_STACKING", "_NET_ACTIVE_WINDOW"})
Expand Down Expand Up @@ -441,6 +449,9 @@ func (tr *Tracker) onStateUpdate(aname string) {
// Update trackable clients
tr.Update()
}

// Write client and workspace cache
tr.Write()
}

func (tr *Tracker) onPointerUpdate(button uint16) {
Expand Down
130 changes: 118 additions & 12 deletions desktop/workspace.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package desktop

import (
"fmt"
"math"
"os"

"encoding/json"
"path/filepath"

"github.com/leukipp/cortile/v2/common"
"github.com/leukipp/cortile/v2/layout"
"github.com/leukipp/cortile/v2/store"
Expand All @@ -9,6 +16,7 @@ import (
)

type Workspace struct {
Name string // Workspace location name
Location store.Location // Desktop and screen location
Layouts []Layout // List of available layouts
TilingEnabled bool // Tiling is enabled or not
Expand All @@ -23,21 +31,38 @@ func CreateWorkspaces() map[store.Location]*Workspace {
location := store.Location{DeskNum: deskNum, ScreenNum: screenNum}

// Create layouts for each desktop and screen
layouts := CreateLayouts(location)
ws := &Workspace{
Name: fmt.Sprintf("workspace-%d-%d", location.DeskNum, location.ScreenNum),
Location: location,
Layouts: layouts,
Layouts: CreateLayouts(location),
TilingEnabled: common.Config.TilingEnabled,
ActiveLayoutNum: 0,
}

// Activate default layout
for i, l := range layouts {
// Set default layout
for i, l := range ws.Layouts {
if l.GetName() == common.Config.TilingLayout {
ws.SetLayout(uint(i))
}
}

// Read workspace from cache
cached := ws.Read()

// Overwrite default layout, proportions and tiling state
ws.SetLayout(cached.ActiveLayoutNum)
for _, l := range ws.Layouts {
for _, cl := range cached.Layouts {
if l.GetName() == cl.GetName() {
mg, cmg := l.GetManager(), cl.GetManager()
mg.Masters.MaxAllowed = int(math.Min(float64(cmg.Masters.MaxAllowed), float64(common.Config.WindowMastersMax)))
mg.Slaves.MaxAllowed = int(math.Min(float64(cmg.Slaves.MaxAllowed), float64(common.Config.WindowSlavesMax)))
mg.Proportions = cmg.Proportions
}
}
}
ws.TilingEnabled = cached.TilingEnabled

// Map location to workspace
workspaces[location] = ws
}
Expand All @@ -46,13 +71,19 @@ func CreateWorkspaces() map[store.Location]*Workspace {
return workspaces
}

func CreateLayouts(l store.Location) []Layout {
func CreateLayouts(loc store.Location) []Layout {
return []Layout{
layout.CreateFullscreenLayout(l.DeskNum, l.ScreenNum),
layout.CreateVerticalLeftLayout(l.DeskNum, l.ScreenNum),
layout.CreateVerticalRightLayout(l.DeskNum, l.ScreenNum),
layout.CreateHorizontalTopLayout(l.DeskNum, l.ScreenNum),
layout.CreateHorizontalBottomLayout(l.DeskNum, l.ScreenNum),
layout.CreateFullscreenLayout(loc),
layout.CreateVerticalLeftLayout(loc),
layout.CreateVerticalRightLayout(loc),
layout.CreateHorizontalTopLayout(loc),
layout.CreateHorizontalBottomLayout(loc),
}
}

func (ws *Workspace) ResetLayouts() {
for _, l := range ws.Layouts {
l.Reset()
}
}

Expand Down Expand Up @@ -110,7 +141,7 @@ func (ws *Workspace) Restore(flag uint8) {
mg := ws.ActiveLayout().GetManager()
clients := mg.Clients(store.Stacked)

log.Info("Untile ", len(clients), " windows [workspace-", mg.DeskNum, "-", mg.ScreenNum, "]")
log.Info("Untile ", len(clients), " windows [", ws.Name, "]")

// Restore client dimensions
for _, c := range clients {
Expand Down Expand Up @@ -138,7 +169,82 @@ func (ws *Workspace) Enabled() bool {

func (ws *Workspace) Disabled() bool {
if ws == nil {
return false
return true
}
return !ws.TilingEnabled
}

func (ws *Workspace) Write() {
if !common.CacheEnabled() {
return
}

// Obtain cache object
cache := ws.Cache()

// Parse workspace cache
data, err := json.MarshalIndent(cache.Data, "", " ")
if err != nil {
log.Warn("Error parsing workspace cache [", ws.Name, "]")
return
}

// Write workspace cache
path := filepath.Join(cache.Folder, cache.Name)
err = os.WriteFile(path, data, 0644)
if err != nil {
log.Warn("Error writing workspace cache [", ws.Name, "]")
return
}

log.Debug("Write workspace cache data ", cache.Name, " [", ws.Name, "]")
}

func (ws *Workspace) Read() *Workspace {
if !common.CacheEnabled() {
return ws
}

// Obtain cache object
cache := ws.Cache()

// Read workspace cache
path := filepath.Join(cache.Folder, cache.Name)
data, err := os.ReadFile(path)
if os.IsNotExist(err) {
log.Info("No workspace cache found [", ws.Name, "]")
return ws
}

// Parse workspace cache
cached := &Workspace{Layouts: CreateLayouts(ws.Location)}
err = json.Unmarshal([]byte(data), &cached)
if err != nil {
log.Warn("Error reading workspace cache [", ws.Name, "]")
return ws
}

log.Debug("Read workspace cache data ", cache.Name, " [", ws.Name, "]")

return cached
}

func (ws *Workspace) Cache() common.Cache[*Workspace] {
name := fmt.Sprintf("workspace-%d", ws.Location.DeskNum)
hash := fmt.Sprintf("%s-%d", name, ws.Location.ScreenNum)

// Create workspace cache folder
folder := filepath.Join(common.Args.Cache, store.Displays.Name, "workspaces", name)
if _, err := os.Stat(folder); os.IsNotExist(err) {
os.MkdirAll(folder, 0755)
}

// Create workspace cache object
cache := common.Cache[*Workspace]{
Folder: folder,
Name: common.Hash(hash) + ".json",
Data: ws,
}

return cache
}
Loading

0 comments on commit 792e864

Please sign in to comment.