Merge branch 'fix/x11-fullscreen-restore' into feat/xwayland-builtin
5 files · +40 -11
M Makefile +1 -1
| @@ -70,7 +70,7 @@ adapter-imports: | |||
| 70 | 70 | [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; } | |
| 71 | 71 | # Fast, mandatory guards for tiled content publications and SHM copies. | |
| 72 | 72 | perf-check: | |
| 73 | - | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations|TestConfigureFlushAllocations|TestFocusAllocations|TestSpaceAllocations|TestUnmanagedGeometryAllocations|TestFocusInUnmanagedAllocations|TestUnmanagedPublishAllocations|TestUnmanagedHitAllocations|TestOverrideMovedUnchangedAllocations|TestFullscreenConfigureAllocations|TestKeyboardGrabSyncAllocations|TestSelectionCopyAllocations|TestSelectionCopyAllocationsWaylandToX|TestSelectionINCRChunkAllocations|TestXSettingsNoChangeAllocations)$$' -count=1 | |
| 73 | + | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations|TestConfigureFlushAllocations|TestFocusAllocations|TestSpaceAllocations|TestUnmanagedGeometryAllocations|TestFocusInUnmanagedAllocations|TestUnmanagedPublishAllocations|TestUnmanagedHitAllocations|TestOverrideMovedUnchangedAllocations|TestFullscreenConfigureAllocations|TestKeyboardGrabSyncAllocations|TestSelectionCopyAllocations|TestSelectionCopyAllocationsWaylandToX|TestSelectionINCRChunkAllocations|TestXSettingsNoChangeAllocations|TestSettleLeftAllocs)$$' -count=1 | |
| 74 | 74 | CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1 | |
| 75 | 75 | check: vet test arch fakes-check log-check perf-check | |
| 76 | 76 | ||
| @@ -70,7 +70,7 @@ adapter-imports: | |||||
| 70 | [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; } | 70 | [ -z "$$bad" ] || { echo "$$bad"; echo 'adapter imports another adapter: use ports or a shared library (Makefile ADAPTER_LIBS)' >&2; exit 1; } | ||
| 71 | # Fast, mandatory guards for tiled content publications and SHM copies. | 71 | # Fast, mandatory guards for tiled content publications and SHM copies. | ||
| 72 | perf-check: | 72 | perf-check: | ||
| 73 | - | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations|TestConfigureFlushAllocations|TestFocusAllocations|TestSpaceAllocations|TestUnmanagedGeometryAllocations|TestFocusInUnmanagedAllocations|TestUnmanagedPublishAllocations|TestUnmanagedHitAllocations|TestOverrideMovedUnchangedAllocations|TestFullscreenConfigureAllocations|TestKeyboardGrabSyncAllocations|TestSelectionCopyAllocations|TestSelectionCopyAllocationsWaylandToX|TestSelectionINCRChunkAllocations|TestXSettingsNoChangeAllocations)$$' -count=1 | 73 | + | CGO_ENABLED=0 go test ./internal/core ./internal/app ./internal/adapters/drm ./internal/adapters/headless ./internal/adapters/vulkan ./internal/adapters/wayland ./internal/adapters/outputkit/capture ./internal/adapters/screencast ./internal/adapters/wayland/xwm -run '^(TestAnimateAllocations|TestPublishAllocations|TestPublishSubscribersAllocations|TestPublishStashSlideAllocations|TestPublishOverviewAllocations|TestPublishLeavingAllocations|TestOutputRoutingAllocations|TestReportSeenAllocations|TestFrameLifecycleTransitionsAllocations|TestFullscreenShownAllocations|TestFrameDecisionAllocations|TestCommitFrameAllocations|TestColorPipelineAllocations|TestShownBySnapshotAllocations|TestFlipShowsAllocations|TestMRUNoteFocusDoesNotAllocateWhenSettled|TestDueFramesAllocations|TestRenderSteadyStateAllocations|TestRenderSteadyStateDMABufAllocations|TestSceneOpaqueRegionAllocations|TestSceneDeltaAllocations|TestAccountFlipAllocations|TestFlipDoneAllocations|TestSceneWalkUnchangedTiledSHM|TestTiledCommitPublishAllocations|TestCapturedCommitApplyAllocations|TestCapturedViewportApplyAllocations|TestEffectiveInputEmptyTreeAllocations|TestHeadlessTiledSHMCallbackAndCopyBudget|TestReleaseHeldAllocations|TestCommitDamageAllocations|TestEmitContentAllocations|TestPresentationPushAllocations|TestAnimatingFrameSendAllocations|TestContentBatchCycleAllocations|TestWriteMappedAllocations|TestCapturedForwardAllocations|TestCommandForwardAllocations|TestOutboxQueuedDeliveryAllocations|TestCastFrameAllocations|TestCastProducerAllocations|TestCaptureCycleAllocations|TestLogScenesAllocations|TestOverviewNamedRowsAllocations|TestBufferContentAllocations|TestDueFramesFireScratch|TestRetireSemaphoreAllocatesNothing|TestTableLookupAllocations|TestTableInsertRemoveAllocations|TestPropertyUnchangedAllocations|TestDispatchAllocations|TestConfigureFlushAllocations|TestFocusAllocations|TestSpaceAllocations|TestUnmanagedGeometryAllocations|TestFocusInUnmanagedAllocations|TestUnmanagedPublishAllocations|TestUnmanagedHitAllocations|TestOverrideMovedUnchangedAllocations|TestFullscreenConfigureAllocations|TestKeyboardGrabSyncAllocations|TestSelectionCopyAllocations|TestSelectionCopyAllocationsWaylandToX|TestSelectionINCRChunkAllocations|TestXSettingsNoChangeAllocations|TestSettleLeftAllocs)$$' -count=1 |
| 74 | CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1 | 74 | CGO_ENABLED=0 go test -tags xturbo_poison ./internal/adapters/wayland/xwm -count=1 | ||
| 75 | check: vet test arch fakes-check log-check perf-check | 75 | check: vet test arch fakes-check log-check perf-check | ||
| 76 | 76 | ||||
M internal/core/core_test.go +2 -3
| @@ -1033,7 +1033,7 @@ func fullscreenAtMapIgnored(t *testing.T, animated bool) { | |||
| 1033 | 1033 | // Under fixed overflow, a window opening over a fullscreen game waits | |
| 1034 | 1034 | // hidden: the game keeps the screen and the keyboard. An activation (a | |
| 1035 | 1035 | // user action in the new client) leaves fullscreen and shows both tiles; | |
| 1036 | - | // a focus move back to the game and the bind make it fullscreen again. | |
| 1036 | + | // a focus move back to the game makes it fullscreen again. | |
| 1037 | 1037 | func TestFixedFullscreenArrivalWaits(t *testing.T) { | |
| 1038 | 1038 | r := startMulti(t, func(c *ports.Config) { c.Layout.Overflow = "fixed" }, left) | |
| 1039 | 1039 | r.mapWindow(t, 1) | |
| @@ -1055,8 +1055,7 @@ func TestFixedFullscreenArrivalWaits(t *testing.T) { | |||
| 1055 | 1055 | break | |
| 1056 | 1056 | } | |
| 1057 | 1057 | } | |
| 1058 | - | r.key(t, "Left", ports.ModAlt) | |
| 1059 | - | set = r.key(t, "f", ports.ModAlt|ports.ModShift) | |
| 1058 | + | set = r.key(t, "Left", ports.ModAlt) | |
| 1060 | 1059 | if got, focused := windowsOf(set, "DP-1"); !reflect.DeepEqual(got, []ports.WindowID{1}) || focused != 1 { | |
| 1061 | 1060 | t.Fatal("game again:", got, focused) | |
| 1062 | 1061 | } | |
| @@ -1033,7 +1033,7 @@ func fullscreenAtMapIgnored(t *testing.T, animated bool) { | |||||
| 1033 | // Under fixed overflow, a window opening over a fullscreen game waits | 1033 | // Under fixed overflow, a window opening over a fullscreen game waits | ||
| 1034 | // hidden: the game keeps the screen and the keyboard. An activation (a | 1034 | // hidden: the game keeps the screen and the keyboard. An activation (a | ||
| 1035 | // user action in the new client) leaves fullscreen and shows both tiles; | 1035 | // user action in the new client) leaves fullscreen and shows both tiles; | ||
| 1036 | - | // a focus move back to the game and the bind make it fullscreen again. | 1036 | + | // a focus move back to the game makes it fullscreen again. |
| 1037 | func TestFixedFullscreenArrivalWaits(t *testing.T) { | 1037 | func TestFixedFullscreenArrivalWaits(t *testing.T) { | ||
| 1038 | r := startMulti(t, func(c *ports.Config) { c.Layout.Overflow = "fixed" }, left) | 1038 | r := startMulti(t, func(c *ports.Config) { c.Layout.Overflow = "fixed" }, left) | ||
| 1039 | r.mapWindow(t, 1) | 1039 | r.mapWindow(t, 1) | ||
| @@ -1055,8 +1055,7 @@ func TestFixedFullscreenArrivalWaits(t *testing.T) { | |||||
| 1055 | break | 1055 | break | ||
| 1056 | } | 1056 | } | ||
| 1057 | } | 1057 | } | ||
| 1058 | - | r.key(t, "Left", ports.ModAlt) | 1058 | + | set = r.key(t, "Left", ports.ModAlt) |
| 1059 | - | set = r.key(t, "f", ports.ModAlt|ports.ModShift) | |||
| 1060 | if got, focused := windowsOf(set, "DP-1"); !reflect.DeepEqual(got, []ports.WindowID{1}) || focused != 1 { | 1059 | if got, focused := windowsOf(set, "DP-1"); !reflect.DeepEqual(got, []ports.WindowID{1}) || focused != 1 { | ||
| 1061 | t.Fatal("game again:", got, focused) | 1060 | t.Fatal("game again:", got, focused) | ||
| 1062 | } | 1061 | } | ||
M internal/core/fullscreen_left_core_test.go +1 -6
| @@ -64,13 +64,8 @@ func TestCoreLeftFullscreenLatch(t *testing.T) { | |||
| 64 | 64 | if id := full(); id != 0 { | |
| 65 | 65 | t.Fatalf("re-request covered: fullscreen %d", id) | |
| 66 | 66 | } | |
| 67 | + | // Focus back on 2 restores its fullscreen: an X11 client never re-asks. | |
| 67 | 68 | client <- ports.WindowActivate{ID: 2} | |
| 68 | - | full() | |
| 69 | - | client <- ports.WindowActivate{ID: 1} | |
| 70 | - | full() | |
| 71 | - | // The latch settled when 2 had the focus: scroll overflow honours an | |
| 72 | - | // unfocused window's request again. | |
| 73 | - | client <- ports.WindowFullscreenRequest{ID: 2, Fullscreen: true} | |
| 74 | 69 | if id := full(); id != 2 { | |
| 75 | 70 | t.Fatalf("after refocus: fullscreen %d, want 2", id) | |
| 76 | 71 | } | |
| @@ -64,13 +64,8 @@ func TestCoreLeftFullscreenLatch(t *testing.T) { | |||||
| 64 | if id := full(); id != 0 { | 64 | if id := full(); id != 0 { | ||
| 65 | t.Fatalf("re-request covered: fullscreen %d", id) | 65 | t.Fatalf("re-request covered: fullscreen %d", id) | ||
| 66 | } | 66 | } | ||
| 67 | + | // Focus back on 2 restores its fullscreen: an X11 client never re-asks. | |||
| 67 | client <- ports.WindowActivate{ID: 2} | 68 | client <- ports.WindowActivate{ID: 2} | ||
| 68 | - | full() | |||
| 69 | - | client <- ports.WindowActivate{ID: 1} | |||
| 70 | - | full() | |||
| 71 | - | // The latch settled when 2 had the focus: scroll overflow honours an | |||
| 72 | - | // unfocused window's request again. | |||
| 73 | - | client <- ports.WindowFullscreenRequest{ID: 2, Fullscreen: true} | |||
| 74 | if id := full(); id != 2 { | 69 | if id := full(); id != 2 { | ||
| 75 | t.Fatalf("after refocus: fullscreen %d, want 2", id) | 70 | t.Fatalf("after refocus: fullscreen %d, want 2", id) | ||
| 76 | } | 71 | } | ||
M internal/core/fullscreen_left_test.go +29 -0
| @@ -111,3 +111,32 @@ func TestLeftFullscreenRemoved(t *testing.T) { | |||
| 111 | 111 | t.Fatalf("left %d", w.left) | |
| 112 | 112 | } | |
| 113 | 113 | } | |
| 114 | + | ||
| 115 | + | // Focus back on a window whose fullscreen the user left restores it, with | |
| 116 | + | // no request from the client (X11 clients never re-ask), and allocates | |
| 117 | + | // nothing once settled. | |
| 118 | + | func TestLeftFullscreenRestoredOnFocus(t *testing.T) { | |
| 119 | + | for _, tc := range pinnedCases { | |
| 120 | + | t.Run(tc.name, func(t *testing.T) { | |
| 121 | + | m := coverMonitor(tc.overflow, tc.float) | |
| 122 | + | w := m.Current() | |
| 123 | + | w.Activate(1) | |
| 124 | + | if w.fullscreen != 0 || w.left != 2 { | |
| 125 | + | t.Fatalf("leave: fullscreen %d, left %d", w.fullscreen, w.left) | |
| 126 | + | } | |
| 127 | + | w.Activate(2) | |
| 128 | + | w.settleLeft() | |
| 129 | + | if w.fullscreen != 2 || w.left != 0 { | |
| 130 | + | t.Fatalf("back: fullscreen %d, left %d", w.fullscreen, w.left) | |
| 131 | + | } | |
| 132 | + | }) | |
| 133 | + | } | |
| 134 | + | } | |
| 135 | + | ||
| 136 | + | func TestSettleLeftAllocs(t *testing.T) { | |
| 137 | + | m := coverMonitor(OverflowScroll, false) | |
| 138 | + | w := m.Current() | |
| 139 | + | if n := testing.AllocsPerRun(100, w.settleLeft); n != 0 { | |
| 140 | + | t.Fatalf("settleLeft allocs %v", n) | |
| 141 | + | } | |
| 142 | + | } | |
| @@ -111,3 +111,32 @@ func TestLeftFullscreenRemoved(t *testing.T) { | |||||
| 111 | t.Fatalf("left %d", w.left) | 111 | t.Fatalf("left %d", w.left) | ||
| 112 | } | 112 | } | ||
| 113 | } | 113 | } | ||
| 114 | + | ||||
| 115 | + | // Focus back on a window whose fullscreen the user left restores it, with | |||
| 116 | + | // no request from the client (X11 clients never re-ask), and allocates | |||
| 117 | + | // nothing once settled. | |||
| 118 | + | func TestLeftFullscreenRestoredOnFocus(t *testing.T) { | |||
| 119 | + | for _, tc := range pinnedCases { | |||
| 120 | + | t.Run(tc.name, func(t *testing.T) { | |||
| 121 | + | m := coverMonitor(tc.overflow, tc.float) | |||
| 122 | + | w := m.Current() | |||
| 123 | + | w.Activate(1) | |||
| 124 | + | if w.fullscreen != 0 || w.left != 2 { | |||
| 125 | + | t.Fatalf("leave: fullscreen %d, left %d", w.fullscreen, w.left) | |||
| 126 | + | } | |||
| 127 | + | w.Activate(2) | |||
| 128 | + | w.settleLeft() | |||
| 129 | + | if w.fullscreen != 2 || w.left != 0 { | |||
| 130 | + | t.Fatalf("back: fullscreen %d, left %d", w.fullscreen, w.left) | |||
| 131 | + | } | |||
| 132 | + | }) | |||
| 133 | + | } | |||
| 134 | + | } | |||
| 135 | + | ||||
| 136 | + | func TestSettleLeftAllocs(t *testing.T) { | |||
| 137 | + | m := coverMonitor(OverflowScroll, false) | |||
| 138 | + | w := m.Current() | |||
| 139 | + | if n := testing.AllocsPerRun(100, w.settleLeft); n != 0 { | |||
| 140 | + | t.Fatalf("settleLeft allocs %v", n) | |||
| 141 | + | } | |||
| 142 | + | } | |||
M internal/core/layout.go +7 -1
| @@ -1435,6 +1435,9 @@ func (w *Workspace) SetFullscreen(id WindowID, on bool) { | |||
| 1435 | 1435 | return | |
| 1436 | 1436 | } | |
| 1437 | 1437 | if !on { | |
| 1438 | + | if w.left == id { | |
| 1439 | + | w.left = 0 // the client itself gave up: nothing to restore | |
| 1440 | + | } | |
| 1438 | 1441 | if w.fullscreen == id { | |
| 1439 | 1442 | w.endFullscreen() | |
| 1440 | 1443 | } | |
| @@ -1522,7 +1525,10 @@ func (w *Workspace) gap() int { return min(w.Gaps, w.Usable.W/2, w.Usable.H/2) } | |||
| 1522 | 1525 | // settleLeft drops the latch once its window has the focus again, however | |
| 1523 | 1526 | // it got it; core calls it after each event. | |
| 1524 | 1527 | func (w *Workspace) settleLeft() { | |
| 1525 | - | if id, ok := w.Focused(); ok && id == w.left { | |
| 1528 | + | if id, ok := w.Focused(); ok && id != 0 && id == w.left { | |
| 1529 | + | // Focus is back: the window gets its fullscreen back, as a client | |
| 1530 | + | // that re-asks would (X11 clients never do). | |
| 1531 | + | w.SetFullscreen(id, true) | |
| 1526 | 1532 | w.left = 0 | |
| 1527 | 1533 | } | |
| 1528 | 1534 | } | |
| @@ -1435,6 +1435,9 @@ func (w *Workspace) SetFullscreen(id WindowID, on bool) { | |||||
| 1435 | return | 1435 | return | ||
| 1436 | } | 1436 | } | ||
| 1437 | if !on { | 1437 | if !on { | ||
| 1438 | + | if w.left == id { | |||
| 1439 | + | w.left = 0 // the client itself gave up: nothing to restore | |||
| 1440 | + | } | |||
| 1438 | if w.fullscreen == id { | 1441 | if w.fullscreen == id { | ||
| 1439 | w.endFullscreen() | 1442 | w.endFullscreen() | ||
| 1440 | } | 1443 | } | ||
| @@ -1522,7 +1525,10 @@ func (w *Workspace) gap() int { return min(w.Gaps, w.Usable.W/2, w.Usable.H/2) } | |||||
| 1522 | // settleLeft drops the latch once its window has the focus again, however | 1525 | // settleLeft drops the latch once its window has the focus again, however | ||
| 1523 | // it got it; core calls it after each event. | 1526 | // it got it; core calls it after each event. | ||
| 1524 | func (w *Workspace) settleLeft() { | 1527 | func (w *Workspace) settleLeft() { | ||
| 1525 | - | if id, ok := w.Focused(); ok && id == w.left { | 1528 | + | if id, ok := w.Focused(); ok && id != 0 && id == w.left { |
| 1529 | + | // Focus is back: the window gets its fullscreen back, as a client | |||
| 1530 | + | // that re-asks would (X11 clients never do). | |||
| 1531 | + | w.SetFullscreen(id, true) | |||
| 1526 | w.left = 0 | 1532 | w.left = 0 | ||
| 1527 | } | 1533 | } | ||
| 1528 | } | 1534 | } | ||