Skip to content

Commit

Permalink
i think i've finally nailed down the state transitions of clients, wo…
Browse files Browse the repository at this point in the history
…rkspaces and layouts.
  • Loading branch information
Andrew Gallant (Ocelot) authored and Andrew Gallant (Ocelot) committed Apr 28, 2012
1 parent d058152 commit 7aaa920
Show file tree
Hide file tree
Showing 9 changed files with 89 additions and 97 deletions.
33 changes: 0 additions & 33 deletions breadcrumbs

This file was deleted.

4 changes: 2 additions & 2 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ type client struct {
transientFor xgb.Id
wmclass *icccm.WmClass

geomStore map[string]*clientGeom
stateStore map[string]*clientState
promptStore map[string]*window

frame Frame
Expand Down Expand Up @@ -72,7 +72,7 @@ func newClient(id xgb.Id) *client {
protocols: nil,
transientFor: 0,
wmclass: nil,
geomStore: make(map[string]*clientGeom),
stateStore: make(map[string]*clientState),
promptStore: make(map[string]*window),
frame: nil,
frameNada: nil,
Expand Down
89 changes: 50 additions & 39 deletions client_geometry.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (

"github.com/BurntSushi/xgbutil/icccm"
"github.com/BurntSushi/xgbutil/xrect"

"github.com/BurntSushi/wingo/logger"
)

func (c *client) GravitizeX(x int, gravity int) int {
Expand Down Expand Up @@ -131,7 +129,7 @@ func (c *client) maximize() {
return
}
if !c.maximized {
c.saveGeom("unmaximized")
c.saveState("unmaximized")
}

c.maximizeRaw()
Expand All @@ -143,7 +141,7 @@ func (c *client) unmaximize() {
}

c.unmaximizeRaw()
c.loadGeom("unmaximized")
c.loadState("unmaximized")
}

func (c *client) maximizeRaw() {
Expand Down Expand Up @@ -211,73 +209,78 @@ func (c *client) moveresizeNoValid(x, y, w, h int) {
c.geomChangeNoValid(DoX|DoY|DoW|DoH, x, y, w, h)
}

type clientGeom struct {
const (
clientStateGeom = 1 << iota
clientStateFrame
clientStateHead
)

var clientStateAll = clientStateGeom | clientStateFrame | clientStateHead

type clientState struct {
xrect.Rect
maximized bool
frame Frame
headGeom xrect.Rect
}

func (c *client) newClientGeom() *clientGeom {
func (c *client) newClientState() *clientState {
var headGeom xrect.Rect = nil
if c.workspace.visible() {
headGeom = xrect.New(xrect.Pieces(c.workspace.headGeom()))
}

return &clientGeom{
return &clientState{
Rect: xrect.New(xrect.Pieces(c.Frame().Geom())),
maximized: c.maximized,
frame: c.frame,
headGeom: headGeom,
}
}

func (c *client) saveGeom(key string) {
c.geomStore[key] = c.newClientGeom()
func (c *client) saveState(key string) {
c.stateStore[key] = c.newClientState()
}

func (c *client) saveGeomTransients(key string) {
func (c *client) saveStateTransients(key string) {
for _, c2 := range WM.clients {
if c.transient(c2) && c2.workspace != nil &&
c2.workspace.id == c.workspace.id {

c2.saveGeom(key)
c2.saveState(key)
}
}
c.saveGeom(key)
c.saveState(key)
}

func (c *client) saveGeomNoClobber(key string) {
if _, ok := c.geomStore[key]; !ok {
c.saveGeom(key)
func (c *client) saveStateNoClobber(key string) {
if _, ok := c.stateStore[key]; !ok {
c.saveState(key)
}
}

func (c *client) copyGeom(src, dest string) {
c.geomStore[dest] = c.geomStore[src]
func (c *client) copyState(src, dest string) {
c.stateStore[dest] = c.stateStore[src]
}

func (c *client) copyGeomTransients(src, dest string) {
func (c *client) copyStateTransients(src, dest string) {
for _, c2 := range WM.clients {
if c.transient(c2) && c2.workspace != nil &&
c2.workspace.id == c.workspace.id {

c2.copyGeom(src, dest)
c2.copyState(src, dest)
}
}
c.copyGeom(src, dest)
c.copyState(src, dest)
}

func (c *client) loadGeom(key string) {
if cgeom, ok := c.geomStore[key]; ok {
c.frameSet(cgeom.frame)
func (c *client) loadState(key string) {
if cgeom, ok := c.stateStore[key]; ok {
newGeom := cgeom.Rect

// let's convert head geometry if need be.
if c.workspace.visible() && cgeom.headGeom != nil &&
c.workspace.headGeom() != cgeom.headGeom {

logger.Debug.Println(c, cgeom.headGeom, c.workspace.headGeom())
newGeom = WM.headConvert(cgeom, cgeom.headGeom,
c.workspace.headGeom())
}
Expand All @@ -287,39 +290,47 @@ func (c *client) loadGeom(key string) {
// "restore" state the client has saved.
c.maximizeRaw()
} else {
c.Frame().ConfigureFrame(
DoX|DoY|DoW|DoH,
newGeom.X(), newGeom.Y(), newGeom.Width(), newGeom.Height(),
0, 0, false, true)
// Only reset this geometry if it isn't finishing a move/resize
if !c.frame.Moving() && !c.frame.Resizing() {
c.Frame().ConfigureFrame(
DoX|DoY|DoW|DoH,
newGeom.X(), newGeom.Y(), newGeom.Width(), newGeom.Height(),
0, 0, false, true)
}
}
delete(c.geomStore, key)

// This comes last, otherwise we might be inspecting the wrong frame
// for information (like whether the client is moving/resizing).
c.frameSet(cgeom.frame)

delete(c.stateStore, key)
}
}

func (c *client) loadGeomTransients(key string) {
func (c *client) loadStateTransients(key string, flags int) {
for _, c2 := range WM.clients {
if c.transient(c2) && c2.workspace != nil &&
c2.workspace.id == c.workspace.id {

c2.loadGeom(key)
c2.loadState(key)
}
}
c.loadGeom(key)
c.loadState(key)
}

func (c *client) deleteGeom(key string) {
if _, ok := c.geomStore[key]; ok {
delete(c.geomStore, key)
func (c *client) deleteState(key string) {
if _, ok := c.stateStore[key]; ok {
delete(c.stateStore, key)
}
}

func (c *client) deleteGeomTransients(key string) {
func (c *client) deleteStateTransients(key string) {
for _, c2 := range WM.clients {
if c.transient(c2) && c2.workspace != nil &&
c2.workspace.id == c.workspace.id {

c2.deleteGeom(key)
c2.deleteState(key)
}
}
c.deleteGeom(key)
c.deleteState(key)
}
20 changes: 14 additions & 6 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,22 +304,30 @@ func cmdHeadFocus(withClient bool, args ...string) func() {
// proper geometry and not its geometry while in a tiling
// layout.
if c.layout().floating() {
c.saveGeomTransients("monitor_switch")
c.saveStateTransients("monitor_switch")
} else {
c.copyGeomTransients(
c.copyStateTransients(
"layout_before_tiling", "monitor_switch")
}
wrk.add(c)

// If the new layout is floating, then load geometry
// in the new monitor. Otherwise, trash the geometry.
// in the new monitor.
// Otherwise... things get tricky. We copy the monitor_switch
// state into "layout_before_tiling." This is because the
// monitor_switch state has the desirable "non-tiling" state.
if c.layout().floating() {
c.loadGeomTransients("monitor_switch")
c.loadStateTransients("monitor_switch", clientStateAll)
} else {
c.deleteGeomTransients("monitor_switch")
c.copyStateTransients(
"monitor_switch", "layout_before_tiling")
c.deleteStateTransients("monitor_switch")
}

// c.Raise()
// Finally, if this window is active, raise it.
if c.state == StateActive {
c.Raise()
}
})
}
wrk.activate(true, greedy)
Expand Down
21 changes: 11 additions & 10 deletions frame_temp.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,12 @@ func frameMoveStep(f Frame, rx, ry, ex, ey int) {
}

func frameMoveEnd(f Frame, rx, ry, ex, ey int) {
FrameReset(f)
WM.headChoose(f.Client(), f.Geom())

moving := f.MovingState()
moving.moving = false
moving.lastRootX, moving.lastRootY = 0, 0
FrameReset(f)
WM.headChoose(f.Client(), f.Geom())
}

func frameResizeBegin(f Frame, direction uint32,
Expand Down Expand Up @@ -208,6 +209,14 @@ func frameResizeStep(f Frame, rx, ry, ex, ey int) {
}

func frameResizeEnd(f Frame, rx, ry, ex, ey int) {
// If windows are really slow to respond/resize, this may be necessary.
// If we don't, it's possible for the client to be out of whack inside
// the decorations.
// Example: Libreoffice in Xephyr. Try resizing it with the mouse and
// releasing the mouse button really quickly.
FrameReset(f)
WM.headChoose(f.Client(), f.Geom())

// just zero out the resizing state
resizing := f.ResizingState()
resizing.resizing = false
Expand All @@ -216,12 +225,4 @@ func frameResizeEnd(f Frame, rx, ry, ex, ey int) {
resizing.width, resizing.height = 0, 0
resizing.xs, resizing.ys = false, false
resizing.ws, resizing.hs = false, false

// If windows are really slow to respond/resize, this may be necessary.
// If we don't, it's possible for the client to be out of whack inside
// the decorations.
// Example: Libreoffice in Xephyr. Try resizing it with the mouse and
// releasing the mouse button really quickly.
FrameReset(f)
WM.headChoose(f.Client(), f.Geom())
}
2 changes: 1 addition & 1 deletion layout_storage.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (ls *layoutStore) remove(c *client) bool {
}

if removed {
c.loadGeom("layout_before_tiling")
c.loadState("layout_before_tiling")
}

return removed
Expand Down
8 changes: 4 additions & 4 deletions layout_tile.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func (ly *tileVertical) place() {
mw = headGeom.Width()
}
for i, item := range ly.store.masters {
item.client.saveGeomNoClobber("layout_before_tiling")
item.client.saveStateNoClobber("layout_before_tiling")
item.client.FrameBorders()
item.client.moveresizeNoValid(mx, headGeom.Y()+i*mh, mw, mh)
}
Expand All @@ -60,7 +60,7 @@ func (ly *tileVertical) place() {
sy := headGeom.Y()
for _, item := range ly.store.slaves {
sh := int(float64(headGeom.Height()) * item.proportion)
item.client.saveGeomNoClobber("layout_before_tiling")
item.client.saveStateNoClobber("layout_before_tiling")
item.client.FrameBorders()
item.client.moveresizeNoValid(sx, sy, sw, sh)
sy += sh
Expand All @@ -76,10 +76,10 @@ func (ly *tileVertical) unplace() {
// with lots of windows appear quicker :-)
for _, c := range WM.stack {
if i := ly.store.mFindClient(c); i > -1 {
ly.store.masters[i].client.loadGeom("layout_before_tiling")
ly.store.masters[i].client.loadState("layout_before_tiling")
}
if i := ly.store.sFindClient(c); i > -1 {
ly.store.slaves[i].client.loadGeom("layout_before_tiling")
ly.store.slaves[i].client.loadState("layout_before_tiling")
}
}
}
Expand Down
5 changes: 5 additions & 0 deletions state_head.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,11 @@ func (wm *state) headsApplyStruts() {
c.maximize()
}
}

// Now make workspaces that are tiling fix themselves.
for _, wrk := range WM.workspaces {
wrk.tile()
}
}

// fillWorkspaces is used when there are more heads than there are workspaces.
Expand Down
4 changes: 2 additions & 2 deletions state_workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func (wrk *workspace) hide() {
for _, c := range WM.clients {
if c.workspace.id == wrk.id {
if c.layout().floating() {
c.saveGeom("workspace_switch")
c.saveState("workspace_switch")
}
c.Unmap()
}
Expand All @@ -285,7 +285,7 @@ func (wrk *workspace) show() {
for _, c := range WM.stack {
if c.workspace.id == wrk.id {
if c.layout().floating() {
c.loadGeom("workspace_switch")
c.loadState("workspace_switch")
}
c.Map()
}
Expand Down

0 comments on commit 7aaa920

Please sign in to comment.