⋯ 597 hidden lines@@ -598,3 +598,75 @@ func TestFlashUnchangedSampleIsReused(t *testing.T) { 598 t.Fatal("changed sample mutated prior scene" ) 598 t.Fatal("changed sample mutated prior scene" ) 599 } 599 } 600 } 600 } 601 + 602 + func TestFlashCrossScreenActionsMarkDestinationOutput(t *testing.T) {603 + for _, tc := range []struct { 604 + name string 605 + action Action 606 + occupied bool 607 + }{ 608 + {"column focus to empty" , ActionFocusColumnRight, false }, 609 + {"column focus to occupied" , ActionFocusColumnRight, true }, 610 + {"monitor focus to empty" , ActionFocusMonitorRight, false }, 611 + {"column move to empty" , ActionMoveColumnRight, false }, 612 + {"column move to occupied" , ActionMoveColumnRight, true }, 613 + } { 614 + t.Run(tc.name, func (t *testing.T) { 615 + c, clock := flashCore(t) 616 + a := c.cur() 617 + c.addScreen(ports.OutputInfo{Name: "B" , Width: 400, Height: 300}) 618 + b := c.screens[1] 619 + if tc.occupied { 620 + c.windows.mapped(ports.WindowMapped{ID: 4}, clock.now) 621 + b.mon.AddWindow(4) 622 + } 623 + c.applyAction(tc.action) 624 + if c.cur() != b { 625 + t.Fatal("action did not cross screens" ) 626 + } 627 + if c.flash.pending == nil || *c.flash.pending != (flashTarget{level: flashMonitor, output: "B" }) { 628 + t.Fatalf("destination request %+v" , c.flash.pending) 629 + } 630 + clock.now = clock.now.Add(flashSettle) 631 + if !c.flashTick() { 632 + t.Fatal("destination flash did not start" ) 633 + } 634 + scenes := stepScenes(t, c, b) 635 + if scenes["A" ].Flash != nil { 636 + t.Fatal("source output flashed" ) 637 + } 638 + f := scenes["B" ].Flash 639 + if f == nil || f.Rect != (Rect{W: 400, H: 300}) || !scenes["B" ].Animating { 640 + t.Fatalf("destination scene flash %+v" , f) 641 + } 642 + if !tc.occupied && tc.action != ActionMoveColumnRight && len(scenes["B" ].Windows) != 0 { 643 + t.Fatal("setup: destination is not empty" ) 644 + } 645 + clock.now = clock.now.Add(c.cfg.Focus.FlashDuration) 646 + scenes = stepScenes(t, c, b) 647 + if scenes["B" ].Flash != nil || c.flashing(a) || c.animating() { 648 + t.Fatal("destination flash did not end" ) 649 + } 650 + }) 651 + } 652 + } 653 + 654 + func TestFlashSameScreenColumnFocusKeepsColumnLevel(t *testing.T) {655 + c, clock := flashCore(t) 656 + sc := c.cur() 657 + c.cur().mon.Current().FocusID(1) 658 + c.applyAction(ActionFocusColumnRight) 659 + if c.cur() != sc || c.flash.pending == nil || c.flash.pending.level != flashColumn { 660 + t.Fatalf("same-screen request %+v" , c.flash.pending) 661 + } 662 + clock.now = clock.now.Add(flashSettle) 663 + if !c.flashTick() { 664 + t.Fatal("column flash did not start" ) 665 + } 666 + s := indicatorScene(t, c) 667 + for _, w := range s.Windows { 668 + if w.ID == c.flash.running.window && s.Flash.Rect != w.Rect { 669 + t.Fatalf("column rect %+v want %+v" , s.Flash.Rect, w.Rect) 670 + } 671 + } 672 + }