From 4348cd56834cb17da5aa9d95d16ddc27bf39e0e6 Mon Sep 17 00:00:00 2001 From: Erik Kurzinger Date: Sat, 20 Oct 2018 18:36:41 +0300 Subject: [PATCH] [effects/presentwindows] Avoid potential freeze during fill-gaps Summary: When using the natural layout algorithm with the fill-gaps option, a small error (less than one) is introduced in windows' aspect ratio each time they are enlarged due to floating-point roundoff. Currently, the algorithm computes the width and height enlargement factors and then attempts to enlarge in each of the four possible directions, repeating until it can't enlarge any windows any further. Hence, this aspect ratio error can be multiplied by up to four. Especially for small, long, and narrow windows, this can result in a total error of greater than one by the end of that loop iteration. If this occurs, on subsequent iterations the height enlargement factor might then be computed as negative violating some of the core assumptions of the algorithm and resulting in the loop iterating endlessly until one of the window dimensions overflows, freezing the program for up to several minutes. To fix this, the height enlargement factor should be re-computed based on the new width each time the window is enlarged, ensuring the error introduced in the aspect ratio never exceeds one. BUG: 364709 BUG: 380865 BUG: 368811 FIXED-IN: 5.15.0 Test Plan: The most reliable way to reproduce the freeze seems to be to activate the desktop-grid effect while a tool-tip window is fading in. Ensure desktop-grid is configured to use present windows, and that present windows is configured to use the natural layout algorithm with the fill gaps option selected. The freeze is still intermittent, but using this method should be able to be triggered within about 10 tries without this fix. After applying the fix, the freeze has never been observed. Reviewers: #kwin, zzag Reviewed By: #kwin, zzag Subscribers: graesslin, kwin, zzag Tags: #kwin Differential Revision: https://phabricator.kde.org/D16278 --- effects/presentwindows/presentwindows.cpp | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index 65a1279479..fa6e579e3b 100755 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -1408,6 +1408,9 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis int xDiff = widthDiff / 2; // Also move a bit in the direction of the enlarge, allows the int yDiff = heightDiff / 2; // center windows to be enlarged if there is gaps on the side. + // heightDiff (and yDiff) will be re-computed after each successfull enlargement attempt + // so that the error introduced in the window's aspect ratio is minimized + // Attempt enlarging to the top-right oldRect = *target; target->setRect(target->x() + xDiff, @@ -1417,8 +1420,11 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis ); if (isOverlappingAny(w, targets, borderRegion)) *target = oldRect; - else + else { moved = true; + heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height(); + yDiff = heightDiff / 2; + } // Attempt enlarging to the bottom-right oldRect = *target; @@ -1430,8 +1436,11 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis ); if (isOverlappingAny(w, targets, borderRegion)) *target = oldRect; - else + else { moved = true; + heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height(); + yDiff = heightDiff / 2; + } // Attempt enlarging to the bottom-left oldRect = *target; @@ -1443,8 +1452,11 @@ void PresentWindowsEffect::calculateWindowTransformationsNatural(EffectWindowLis ); if (isOverlappingAny(w, targets, borderRegion)) *target = oldRect; - else + else { moved = true; + heightDiff = heightForWidth(w, target->width() + widthDiff) - target->height(); + yDiff = heightDiff / 2; + } // Attempt enlarging to the top-left oldRect = *target;