fix(layout): track the fullscreen window by id, dialogs float and follow it home
- commit
- 12f359fcd1cb5492751a2ff95aae8ad9cbef29e4
- author
- brice · · 2026-09-25 20:20 UTC
- parent
- 461a201
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
3 files · +74 -24
M internal/core/layout.go +2 -0
| @@ -145,6 +145,8 @@ type Workspace struct { | |||
| 145 | 145 | // origPlace remembers where a window was: its column, its row in a stacked | |
| 146 | 146 | // column, the column's width and slot, or its floating size. | |
| 147 | 147 | type origPlace struct { | |
| 148 | + | // id is the window that went fullscreen. | |
| 149 | + | id WindowID | |
| 148 | 150 | col, row, slot int | |
| 149 | 151 | // stacked holds the windows left in the column: the window returns to | |
| 150 | 152 | // its row in the column that still holds one of them. | |
| @@ -145,6 +145,8 @@ type Workspace struct { | |||||
| 145 | // origPlace remembers where a window was: its column, its row in a stacked | 145 | // origPlace remembers where a window was: its column, its row in a stacked | ||
| 146 | // column, the column's width and slot, or its floating size. | 146 | // column, the column's width and slot, or its floating size. | ||
| 147 | type origPlace struct { | 147 | type origPlace struct { | ||
| 148 | + | // id is the window that went fullscreen. | |||
| 149 | + | id WindowID | |||
| 148 | col, row, slot int | 150 | col, row, slot int | ||
| 149 | // stacked holds the windows left in the column: the window returns to | 151 | // stacked holds the windows left in the column: the window returns to | ||
| 150 | // its row in the column that still holds one of them. | 152 | // its row in the column that still holds one of them. | ||
M internal/core/monitor.go +47 -21
| @@ -223,11 +223,18 @@ func (m *Monitor) find(id WindowID) (*Workspace, int) { | |||
| 223 | 223 | return nil, -1 | |
| 224 | 224 | } | |
| 225 | 225 | ||
| 226 | - | // AddWindow places a new window on the workspace on screen. | |
| 226 | + | // AddWindow places a new window on the workspace on screen. On a | |
| 227 | + | // fullscreen workspace it floats, above the fullscreen window: a tiled one | |
| 228 | + | // would be hidden behind it (fixed overflow) while it has the focus. | |
| 227 | 229 | func (m *Monitor) AddWindow(id WindowID) { | |
| 228 | 230 | if w, _ := m.find(id); w != nil { | |
| 229 | 231 | return | |
| 230 | 232 | } | |
| 233 | + | if cur := m.Current(); cur.origin != nil { | |
| 234 | + | cur.AddFloating(id, 0, 0) | |
| 235 | + | m.normalize() | |
| 236 | + | return | |
| 237 | + | } | |
| 231 | 238 | m.Current().AddWindow(id) | |
| 232 | 239 | m.normalize() | |
| 233 | 240 | } | |
| @@ -245,14 +252,14 @@ func (m *Monitor) AddFloating(id WindowID, width, height int) { | |||
| 245 | 252 | // workspace, except that closing a fullscreen workspace goes back to its origin. | |
| 246 | 253 | func (m *Monitor) RemoveWindow(id WindowID) { | |
| 247 | 254 | if w, _ := m.find(id); w != nil { | |
| 248 | - | w.RemoveWindow(id) | |
| 249 | - | if w.origin != nil && w.empty() && m.has(w.origin) { | |
| 250 | - | shown := m.Current() == w | |
| 251 | - | origin := w.origin | |
| 252 | - | m.take(w) | |
| 253 | - | if shown { | |
| 254 | - | m.show(origin) | |
| 255 | - | } | |
| 255 | + | if w.origin != nil && id == w.back.id && m.has(w.origin) { | |
| 256 | + | // Its dialogs go home with the view. | |
| 257 | + | origin, at := w.origin, w.back.col | |
| 258 | + | w.RemoveWindow(id) | |
| 259 | + | w.origin, w.back = nil, origPlace{} | |
| 260 | + | m.foldInto(w, origin, at, false) | |
| 261 | + | } else { | |
| 262 | + | w.RemoveWindow(id) | |
| 256 | 263 | } | |
| 257 | 264 | m.normalize() | |
| 258 | 265 | } | |
| @@ -286,7 +293,8 @@ func (m *Monitor) ToggleFullscreen() { | |||
| 286 | 293 | id, ok := w.Focused() | |
| 287 | 294 | switch { | |
| 288 | 295 | case !ok: | |
| 289 | - | case w.origin != nil && w.fullscreen == id: | |
| 296 | + | case w.origin != nil && w.fullscreen == w.back.id: | |
| 297 | + | // From its window or one of its dialogs. | |
| 290 | 298 | m.leaveFullscreen(w, true) | |
| 291 | 299 | case m.ownWorkspace(w, id): | |
| 292 | 300 | m.enterFullscreen(w, id, true) | |
| @@ -311,6 +319,7 @@ func (m *Monitor) enterFullscreen(w *Workspace, id WindowID, show bool) { | |||
| 311 | 319 | fs := m.newWorkspace() | |
| 312 | 320 | fs.Overflow, fs.MaxColumns = w.Overflow, w.MaxColumns | |
| 313 | 321 | fs.origin = w | |
| 322 | + | fs.back.id = id | |
| 314 | 323 | if f := w.floatIndex(id); f >= 0 { | |
| 315 | 324 | fl := w.Floats[f] | |
| 316 | 325 | fs.back.float = &fl | |
| @@ -319,7 +328,7 @@ func (m *Monitor) enterFullscreen(w *Workspace, id WindowID, show bool) { | |||
| 319 | 328 | } else { | |
| 320 | 329 | col := slices.IndexFunc(w.Columns, func(c Column) bool { return slices.Contains(c.Windows, id) }) | |
| 321 | 330 | c := w.Columns[col] | |
| 322 | - | fs.back = origPlace{col: col, row: slices.Index(c.Windows, id), slot: c.Slot, width: c.Width} | |
| 331 | + | fs.back = origPlace{id: id, col: col, row: slices.Index(c.Windows, id), slot: c.Slot, width: c.Width} | |
| 323 | 332 | for _, v := range c.Windows { | |
| 324 | 333 | if v != id { | |
| 325 | 334 | fs.back.stacked = append(fs.back.stacked, v) | |
| @@ -343,17 +352,19 @@ func (m *Monitor) enterFullscreen(w *Workspace, id WindowID, show bool) { | |||
| 343 | 352 | } | |
| 344 | 353 | } | |
| 345 | 354 | ||
| 346 | - | // leaveFullscreen sends the window of fs back to its place in the origin | |
| 347 | - | // and drops fs; the view goes along when fs was on screen. focus is set | |
| 348 | - | // for the user's bind: the window gets the focus back there. | |
| 355 | + | // leaveFullscreen sends the window of fs back to its place in the origin, | |
| 356 | + | // with the windows opened there meanwhile (its dialogs) just after it, and | |
| 357 | + | // drops fs; the view goes along when fs was on screen. focus is set when | |
| 358 | + | // the user was on the window: it gets the focus back there. | |
| 349 | 359 | func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) { | |
| 350 | 360 | if m.fullscreenHome(); fs.origin == nil { | |
| 351 | 361 | fs.SetFullscreen(fs.fullscreen, false) | |
| 352 | 362 | return | |
| 353 | 363 | } | |
| 354 | - | origin, back, id := fs.origin, fs.back, fs.fullscreen | |
| 364 | + | origin, back, id := fs.origin, fs.back, fs.back.id | |
| 355 | 365 | fs.origin, fs.back = nil, origPlace{} | |
| 356 | 366 | fs.RemoveWindow(id) | |
| 367 | + | defer m.foldInto(fs, origin, back.col+1, focus) | |
| 357 | 368 | switch prev := origin.Focus; { | |
| 358 | 369 | case back.float != nil && focus: | |
| 359 | 370 | origin.AddFloating(id, back.float.W, back.float.H) | |
| @@ -389,20 +400,35 @@ func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) { | |||
| 389 | 400 | } | |
| 390 | 401 | } | |
| 391 | 402 | } | |
| 403 | + | } | |
| 404 | + | ||
| 405 | + | // foldInto moves what is left in fs (windows opened while fullscreen: its | |
| 406 | + | // dialogs) to origin, tiled ones from column at, floating ones on top, and | |
| 407 | + | // drops fs. The view goes along when fs was on screen. | |
| 408 | + | func (m *Monitor) foldInto(fs, origin *Workspace, at int, focus bool) { | |
| 409 | + | shown := m.Current() == fs | |
| 410 | + | at = min(max(at, 0), len(origin.Columns)) | |
| 411 | + | for _, c := range slices.Backward(fs.Columns) { | |
| 412 | + | origin.Columns = slices.Insert(origin.Columns, at, Column{Windows: c.Windows, Width: c.Width, Focus: c.Focus}) | |
| 413 | + | if at <= origin.Focus && len(origin.Columns) > 1 { | |
| 414 | + | origin.Focus++ | |
| 415 | + | } | |
| 416 | + | } | |
| 417 | + | origin.Floats = append(origin.Floats, fs.Floats...) | |
| 418 | + | origin.floatFocus = origin.floatFocus || len(fs.Floats) > 0 && (focus || shown) && fs.floatFocus | |
| 419 | + | fs.Columns, fs.Floats = nil, nil | |
| 392 | 420 | origin.scroll() | |
| 393 | - | if m.Current() == fs && (focus || fs.empty()) { | |
| 421 | + | m.take(fs) | |
| 422 | + | if shown { | |
| 394 | 423 | m.show(origin) | |
| 395 | 424 | } | |
| 396 | - | if fs.empty() { | |
| 397 | - | m.take(fs) | |
| 398 | - | } | |
| 399 | 425 | } | |
| 400 | 426 | ||
| 401 | 427 | // awayInSlot reports whether id is away from slot n of w, fullscreen in a | |
| 402 | 428 | // workspace that returns it there. | |
| 403 | 429 | func (m *Monitor) awayInSlot(w *Workspace, id WindowID, n int) bool { | |
| 404 | 430 | for _, fs := range m.all() { | |
| 405 | - | if fs.origin == w && fs.fullscreen == id && fs.back.slot == n { | |
| 431 | + | if fs.origin == w && fs.back.id == id && fs.back.slot == n { | |
| 406 | 432 | return true | |
| 407 | 433 | } | |
| 408 | 434 | } | |
| @@ -424,7 +450,7 @@ func (m *Monitor) fullscreenHome() { | |||
| 424 | 450 | if w.origin == nil { | |
| 425 | 451 | continue | |
| 426 | 452 | } | |
| 427 | - | if !m.has(w.origin) || w.fullscreen == 0 || !w.has(w.fullscreen) { | |
| 453 | + | if !m.has(w.origin) || w.fullscreen != w.back.id || !w.has(w.back.id) { | |
| 428 | 454 | w.origin, w.back = nil, origPlace{} | |
| 429 | 455 | } | |
| 430 | 456 | } | |
| @@ -223,11 +223,18 @@ func (m *Monitor) find(id WindowID) (*Workspace, int) { | |||||
| 223 | return nil, -1 | 223 | return nil, -1 | ||
| 224 | } | 224 | } | ||
| 225 | 225 | ||||
| 226 | - | // AddWindow places a new window on the workspace on screen. | 226 | + | // AddWindow places a new window on the workspace on screen. On a |
| 227 | + | // fullscreen workspace it floats, above the fullscreen window: a tiled one | |||
| 228 | + | // would be hidden behind it (fixed overflow) while it has the focus. | |||
| 227 | func (m *Monitor) AddWindow(id WindowID) { | 229 | func (m *Monitor) AddWindow(id WindowID) { | ||
| 228 | if w, _ := m.find(id); w != nil { | 230 | if w, _ := m.find(id); w != nil { | ||
| 229 | return | 231 | return | ||
| 230 | } | 232 | } | ||
| 233 | + | if cur := m.Current(); cur.origin != nil { | |||
| 234 | + | cur.AddFloating(id, 0, 0) | |||
| 235 | + | m.normalize() | |||
| 236 | + | return | |||
| 237 | + | } | |||
| 231 | m.Current().AddWindow(id) | 238 | m.Current().AddWindow(id) | ||
| 232 | m.normalize() | 239 | m.normalize() | ||
| 233 | } | 240 | } | ||
| @@ -245,14 +252,14 @@ func (m *Monitor) AddFloating(id WindowID, width, height int) { | |||||
| 245 | // workspace, except that closing a fullscreen workspace goes back to its origin. | 252 | // workspace, except that closing a fullscreen workspace goes back to its origin. | ||
| 246 | func (m *Monitor) RemoveWindow(id WindowID) { | 253 | func (m *Monitor) RemoveWindow(id WindowID) { | ||
| 247 | if w, _ := m.find(id); w != nil { | 254 | if w, _ := m.find(id); w != nil { | ||
| 248 | - | w.RemoveWindow(id) | 255 | + | if w.origin != nil && id == w.back.id && m.has(w.origin) { |
| 249 | - | if w.origin != nil && w.empty() && m.has(w.origin) { | 256 | + | // Its dialogs go home with the view. |
| 250 | - | shown := m.Current() == w | 257 | + | origin, at := w.origin, w.back.col |
| 251 | - | origin := w.origin | 258 | + | w.RemoveWindow(id) |
| 252 | - | m.take(w) | 259 | + | w.origin, w.back = nil, origPlace{} |
| 253 | - | if shown { | 260 | + | m.foldInto(w, origin, at, false) |
| 254 | - | m.show(origin) | 261 | + | } else { |
| 255 | - | } | 262 | + | w.RemoveWindow(id) |
| 256 | } | 263 | } | ||
| 257 | m.normalize() | 264 | m.normalize() | ||
| 258 | } | 265 | } | ||
| @@ -286,7 +293,8 @@ func (m *Monitor) ToggleFullscreen() { | |||||
| 286 | id, ok := w.Focused() | 293 | id, ok := w.Focused() | ||
| 287 | switch { | 294 | switch { | ||
| 288 | case !ok: | 295 | case !ok: | ||
| 289 | - | case w.origin != nil && w.fullscreen == id: | 296 | + | case w.origin != nil && w.fullscreen == w.back.id: |
| 297 | + | // From its window or one of its dialogs. | |||
| 290 | m.leaveFullscreen(w, true) | 298 | m.leaveFullscreen(w, true) | ||
| 291 | case m.ownWorkspace(w, id): | 299 | case m.ownWorkspace(w, id): | ||
| 292 | m.enterFullscreen(w, id, true) | 300 | m.enterFullscreen(w, id, true) | ||
| @@ -311,6 +319,7 @@ func (m *Monitor) enterFullscreen(w *Workspace, id WindowID, show bool) { | |||||
| 311 | fs := m.newWorkspace() | 319 | fs := m.newWorkspace() | ||
| 312 | fs.Overflow, fs.MaxColumns = w.Overflow, w.MaxColumns | 320 | fs.Overflow, fs.MaxColumns = w.Overflow, w.MaxColumns | ||
| 313 | fs.origin = w | 321 | fs.origin = w | ||
| 322 | + | fs.back.id = id | |||
| 314 | if f := w.floatIndex(id); f >= 0 { | 323 | if f := w.floatIndex(id); f >= 0 { | ||
| 315 | fl := w.Floats[f] | 324 | fl := w.Floats[f] | ||
| 316 | fs.back.float = &fl | 325 | fs.back.float = &fl | ||
| @@ -319,7 +328,7 @@ func (m *Monitor) enterFullscreen(w *Workspace, id WindowID, show bool) { | |||||
| 319 | } else { | 328 | } else { | ||
| 320 | col := slices.IndexFunc(w.Columns, func(c Column) bool { return slices.Contains(c.Windows, id) }) | 329 | col := slices.IndexFunc(w.Columns, func(c Column) bool { return slices.Contains(c.Windows, id) }) | ||
| 321 | c := w.Columns[col] | 330 | c := w.Columns[col] | ||
| 322 | - | fs.back = origPlace{col: col, row: slices.Index(c.Windows, id), slot: c.Slot, width: c.Width} | 331 | + | fs.back = origPlace{id: id, col: col, row: slices.Index(c.Windows, id), slot: c.Slot, width: c.Width} |
| 323 | for _, v := range c.Windows { | 332 | for _, v := range c.Windows { | ||
| 324 | if v != id { | 333 | if v != id { | ||
| 325 | fs.back.stacked = append(fs.back.stacked, v) | 334 | fs.back.stacked = append(fs.back.stacked, v) | ||
| @@ -343,17 +352,19 @@ func (m *Monitor) enterFullscreen(w *Workspace, id WindowID, show bool) { | |||||
| 343 | } | 352 | } | ||
| 344 | } | 353 | } | ||
| 345 | 354 | ||||
| 346 | - | // leaveFullscreen sends the window of fs back to its place in the origin | 355 | + | // leaveFullscreen sends the window of fs back to its place in the origin, |
| 347 | - | // and drops fs; the view goes along when fs was on screen. focus is set | 356 | + | // with the windows opened there meanwhile (its dialogs) just after it, and |
| 348 | - | // for the user's bind: the window gets the focus back there. | 357 | + | // drops fs; the view goes along when fs was on screen. focus is set when |
| 358 | + | // the user was on the window: it gets the focus back there. | |||
| 349 | func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) { | 359 | func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) { | ||
| 350 | if m.fullscreenHome(); fs.origin == nil { | 360 | if m.fullscreenHome(); fs.origin == nil { | ||
| 351 | fs.SetFullscreen(fs.fullscreen, false) | 361 | fs.SetFullscreen(fs.fullscreen, false) | ||
| 352 | return | 362 | return | ||
| 353 | } | 363 | } | ||
| 354 | - | origin, back, id := fs.origin, fs.back, fs.fullscreen | 364 | + | origin, back, id := fs.origin, fs.back, fs.back.id |
| 355 | fs.origin, fs.back = nil, origPlace{} | 365 | fs.origin, fs.back = nil, origPlace{} | ||
| 356 | fs.RemoveWindow(id) | 366 | fs.RemoveWindow(id) | ||
| 367 | + | defer m.foldInto(fs, origin, back.col+1, focus) | |||
| 357 | switch prev := origin.Focus; { | 368 | switch prev := origin.Focus; { | ||
| 358 | case back.float != nil && focus: | 369 | case back.float != nil && focus: | ||
| 359 | origin.AddFloating(id, back.float.W, back.float.H) | 370 | origin.AddFloating(id, back.float.W, back.float.H) | ||
| @@ -389,20 +400,35 @@ func (m *Monitor) leaveFullscreen(fs *Workspace, focus bool) { | |||||
| 389 | } | 400 | } | ||
| 390 | } | 401 | } | ||
| 391 | } | 402 | } | ||
| 403 | + | } | |||
| 404 | + | ||||
| 405 | + | // foldInto moves what is left in fs (windows opened while fullscreen: its | |||
| 406 | + | // dialogs) to origin, tiled ones from column at, floating ones on top, and | |||
| 407 | + | // drops fs. The view goes along when fs was on screen. | |||
| 408 | + | func (m *Monitor) foldInto(fs, origin *Workspace, at int, focus bool) { | |||
| 409 | + | shown := m.Current() == fs | |||
| 410 | + | at = min(max(at, 0), len(origin.Columns)) | |||
| 411 | + | for _, c := range slices.Backward(fs.Columns) { | |||
| 412 | + | origin.Columns = slices.Insert(origin.Columns, at, Column{Windows: c.Windows, Width: c.Width, Focus: c.Focus}) | |||
| 413 | + | if at <= origin.Focus && len(origin.Columns) > 1 { | |||
| 414 | + | origin.Focus++ | |||
| 415 | + | } | |||
| 416 | + | } | |||
| 417 | + | origin.Floats = append(origin.Floats, fs.Floats...) | |||
| 418 | + | origin.floatFocus = origin.floatFocus || len(fs.Floats) > 0 && (focus || shown) && fs.floatFocus | |||
| 419 | + | fs.Columns, fs.Floats = nil, nil | |||
| 392 | origin.scroll() | 420 | origin.scroll() | ||
| 393 | - | if m.Current() == fs && (focus || fs.empty()) { | 421 | + | m.take(fs) |
| 422 | + | if shown { | |||
| 394 | m.show(origin) | 423 | m.show(origin) | ||
| 395 | } | 424 | } | ||
| 396 | - | if fs.empty() { | |||
| 397 | - | m.take(fs) | |||
| 398 | - | } | |||
| 399 | } | 425 | } | ||
| 400 | 426 | ||||
| 401 | // awayInSlot reports whether id is away from slot n of w, fullscreen in a | 427 | // awayInSlot reports whether id is away from slot n of w, fullscreen in a | ||
| 402 | // workspace that returns it there. | 428 | // workspace that returns it there. | ||
| 403 | func (m *Monitor) awayInSlot(w *Workspace, id WindowID, n int) bool { | 429 | func (m *Monitor) awayInSlot(w *Workspace, id WindowID, n int) bool { | ||
| 404 | for _, fs := range m.all() { | 430 | for _, fs := range m.all() { | ||
| 405 | - | if fs.origin == w && fs.fullscreen == id && fs.back.slot == n { | 431 | + | if fs.origin == w && fs.back.id == id && fs.back.slot == n { |
| 406 | return true | 432 | return true | ||
| 407 | } | 433 | } | ||
| 408 | } | 434 | } | ||
| @@ -424,7 +450,7 @@ func (m *Monitor) fullscreenHome() { | |||||
| 424 | if w.origin == nil { | 450 | if w.origin == nil { | ||
| 425 | continue | 451 | continue | ||
| 426 | } | 452 | } | ||
| 427 | - | if !m.has(w.origin) || w.fullscreen == 0 || !w.has(w.fullscreen) { | 453 | + | if !m.has(w.origin) || w.fullscreen != w.back.id || !w.has(w.back.id) { |
| 428 | w.origin, w.back = nil, origPlace{} | 454 | w.origin, w.back = nil, origPlace{} | ||
| 429 | } | 455 | } | ||
| 430 | } | 456 | } | ||
M internal/core/monitor_test.go +25 -3
| @@ -487,14 +487,36 @@ func TestMonitorFixedFullscreenEdges(t *testing.T) { | |||
| 487 | 487 | } | |
| 488 | 488 | return m | |
| 489 | 489 | } | |
| 490 | - | t.Run("a window opened there stays when it returns", func(t *testing.T) { | |
| 490 | + | t.Run("a dialog opened there floats and follows it home", func(t *testing.T) { | |
| 491 | 491 | m := fixed() | |
| 492 | 492 | m.Current().FocusID(2) | |
| 493 | 493 | m.ToggleFullscreen() | |
| 494 | 494 | m.AddWindow(4) | |
| 495 | - | m.Current().MoveColumn(-1) | |
| 495 | + | if fs := m.Current(); fs.floatIndex(4) != 0 || fs.fullscreen != 2 { | |
| 496 | + | t.Fatal(fs.Floats, fs.fullscreen) | |
| 497 | + | } | |
| 496 | 498 | m.SetFullscreen(2, false) | |
| 497 | - | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 2, 3}, {4}, {}}) || m.Active != 0 { | |
| 499 | + | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 2, 3}, {}}) || m.Active != 0 || m.Current().floatIndex(4) != 0 { | |
| 500 | + | t.Fatal(got, m.Active, m.Current().Floats) | |
| 501 | + | } | |
| 502 | + | }) | |
| 503 | + | t.Run("the bind from a dialog returns the fullscreen window", func(t *testing.T) { | |
| 504 | + | m := fixed() | |
| 505 | + | m.Current().FocusID(2) | |
| 506 | + | m.ToggleFullscreen() | |
| 507 | + | m.AddWindow(4) // focused dialog | |
| 508 | + | m.ToggleFullscreen() | |
| 509 | + | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 2, 3}, {}}) || m.Current().floatIndex(4) != 0 { | |
| 510 | + | t.Fatal(got, m.Current().Floats) | |
| 511 | + | } | |
| 512 | + | }) | |
| 513 | + | t.Run("closing it brings its dialogs home", func(t *testing.T) { | |
| 514 | + | m := fixed() | |
| 515 | + | m.Current().FocusID(2) | |
| 516 | + | m.ToggleFullscreen() | |
| 517 | + | m.AddWindow(4) | |
| 518 | + | m.RemoveWindow(2) | |
| 519 | + | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 3}, {}}) || m.Active != 0 || m.Current().floatIndex(4) != 0 { | |
| 498 | 520 | t.Fatal(got, m.Active) | |
| 499 | 521 | } | |
| 500 | 522 | }) | |
| @@ -487,14 +487,36 @@ func TestMonitorFixedFullscreenEdges(t *testing.T) { | |||||
| 487 | } | 487 | } | ||
| 488 | return m | 488 | return m | ||
| 489 | } | 489 | } | ||
| 490 | - | t.Run("a window opened there stays when it returns", func(t *testing.T) { | 490 | + | t.Run("a dialog opened there floats and follows it home", func(t *testing.T) { |
| 491 | m := fixed() | 491 | m := fixed() | ||
| 492 | m.Current().FocusID(2) | 492 | m.Current().FocusID(2) | ||
| 493 | m.ToggleFullscreen() | 493 | m.ToggleFullscreen() | ||
| 494 | m.AddWindow(4) | 494 | m.AddWindow(4) | ||
| 495 | - | m.Current().MoveColumn(-1) | 495 | + | if fs := m.Current(); fs.floatIndex(4) != 0 || fs.fullscreen != 2 { |
| 496 | + | t.Fatal(fs.Floats, fs.fullscreen) | |||
| 497 | + | } | |||
| 496 | m.SetFullscreen(2, false) | 498 | m.SetFullscreen(2, false) | ||
| 497 | - | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 2, 3}, {4}, {}}) || m.Active != 0 { | 499 | + | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 2, 3}, {}}) || m.Active != 0 || m.Current().floatIndex(4) != 0 { |
| 500 | + | t.Fatal(got, m.Active, m.Current().Floats) | |||
| 501 | + | } | |||
| 502 | + | }) | |||
| 503 | + | t.Run("the bind from a dialog returns the fullscreen window", func(t *testing.T) { | |||
| 504 | + | m := fixed() | |||
| 505 | + | m.Current().FocusID(2) | |||
| 506 | + | m.ToggleFullscreen() | |||
| 507 | + | m.AddWindow(4) // focused dialog | |||
| 508 | + | m.ToggleFullscreen() | |||
| 509 | + | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 2, 3}, {}}) || m.Current().floatIndex(4) != 0 { | |||
| 510 | + | t.Fatal(got, m.Current().Floats) | |||
| 511 | + | } | |||
| 512 | + | }) | |||
| 513 | + | t.Run("closing it brings its dialogs home", func(t *testing.T) { | |||
| 514 | + | m := fixed() | |||
| 515 | + | m.Current().FocusID(2) | |||
| 516 | + | m.ToggleFullscreen() | |||
| 517 | + | m.AddWindow(4) | |||
| 518 | + | m.RemoveWindow(2) | |||
| 519 | + | if got := windows(m); !reflect.DeepEqual(got, [][]WindowID{{1, 3}, {}}) || m.Active != 0 || m.Current().floatIndex(4) != 0 { | |||
| 498 | t.Fatal(got, m.Active) | 520 | t.Fatal(got, m.Active) | ||
| 499 | } | 521 | } | ||
| 500 | }) | 522 | }) | ||