From cc9a95df5d5fc73becbaeee69bf0d59257cc0749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Sat, 6 Jun 2015 21:11:53 +0200 Subject: [PATCH] evenly distribute windows into all corners If the user has only maximized windows or all windows crammed into one region of the screen the effect would not resemble an aperture at all this ensures a maximum amount of corners is used while seeking to still use shortest paths BUG: 348709 FIXED-IN: 5.4 --- .../package/contents/code/main.js | 177 +++++++++++------- 1 file changed, 114 insertions(+), 63 deletions(-) diff --git a/effects/windowaperture/package/contents/code/main.js b/effects/windowaperture/package/contents/code/main.js index 52396a6781..8c55e840fa 100644 --- a/effects/windowaperture/package/contents/code/main.js +++ b/effects/windowaperture/package/contents/code/main.js @@ -31,43 +31,23 @@ var badBadWindowsEffect = { var screenGeo = effects.virtualScreenGeometry; var xOffset = screenGeo.width / 16; var yOffset = screenGeo.height / 16; - for (var i = 0; i < stackingOrder.length; ++i) { - var w = stackingOrder[i]; + if (showing) { + var closestWindows = [ undefined, undefined, undefined, undefined ]; + var movedWindowsCount = 0; + for (var i = 0; i < stackingOrder.length; ++i) { + var w = stackingOrder[i]; - // ignore windows above the desktop (when not showing, pretty much everything would be) - if (w.desktopWindow && showing) - break; + // ignore windows above the desktop + // (when not showing, pretty much everything would be) + if (w.desktopWindow) + break; - // ignore invisible windows and such that do not have to be restored - if (!w.visible) { - if (!(showing || w.offToCornerId === undefined)) { // we still need to stop this - cancel(w.offToCornerId); - delete w.offToCornerId; - effects.setElevatedWindow(w, false); - if (!w.dock) { - animate({ - window: w, - duration: badBadWindowsEffect.duration, - animations: [{ - type: Effect.Opacity, - from: 0.2, - to: 0.0 - }] - }); - } - } - continue; - } - if (!showing && w.offToCornerId === undefined) { - continue; - } + // ignore invisible windows and such that do not have to be restored + if (!w.visible) + continue; - // keep windows above the desktop visually - effects.setElevatedWindow(w, showing); - - // we just fade out docks - moving panels into edges looks dull - if (w.dock) { - if (showing) { + // we just fade out docks - moving panels into edges looks dull + if (w.dock) { w.offToCornerId = set({ window: w, duration: badBadWindowsEffect.duration, @@ -76,32 +56,101 @@ var badBadWindowsEffect = { to: 0.0 }] }); - } else { - cancel(w.offToCornerId); - delete w.offToCornerId; - animate({ - window: w, - duration: badBadWindowsEffect.duration, - animations: [{ - type: Effect.Opacity, - from: 0.0 - }] - }); + continue; } - continue; // ! ;-) + + // calculate the corner distances + var geo = w.geometry; + var dl = geo.x + geo.width - screenGeo.x; + var dr = screenGeo.x + screenGeo.width - geo.x; + var dt = geo.y + geo.height - screenGeo.y; + var db = screenGeo.y + screenGeo.height - geo.y; + w.apertureDistances = [ dl + dt, dr + dt, dr + db, dl + db ]; + movedWindowsCount += 1; + + // if this window is the closest one to any corner, set it as preferred there + var nearest = 0; + for (var j = 1; j < 4; ++j) { + if (w.apertureDistances[j] < w.apertureDistances[nearest] || + (w.apertureDistances[j] == w.apertureDistances[nearest] && closestWindows[j] === undefined)) { + nearest = j; + } + } + if (closestWindows[nearest] === undefined || + closestWindows[nearest].apertureDistances[nearest] > w.apertureDistances[nearest]) + closestWindows[nearest] = w; + } + + // second pass, select corners + + // 1st off, move the nearest windows to their nearest corners + // this will ensure that if there's only on window in the lower right + // it won't be moved out to the upper left + var movedWindowsDec = [ 0, 0, 0, 0 ]; + for (var i = 0; i < 4; ++i) { + if (closestWindows[i] === undefined) + continue; + closestWindows[i].apertureCorner = i; + delete closestWindows[i].apertureDistances; + movedWindowsDec[i] = 1; + } + + // 2nd, distribute the remainders according to their preferences + // this doesn't exactly have heapsort performance ;-) + movedWindowsCount = Math.floor((movedWindowsCount + 3) / 4); + for (var i = 0; i < 4; ++i) { + for (var j = 0; j < movedWindowsCount - movedWindowsDec[i]; ++j) { + var bestWindow = undefined; + for (var k = 0; k < stackingOrder.length; ++k) { + if (stackingOrder[k].apertureDistances === undefined) + continue; + if (bestWindow === undefined || + stackingOrder[k].apertureDistances[i] < bestWindow.apertureDistances[i]) + bestWindow = stackingOrder[k]; + } + if (bestWindow === undefined) + break; + bestWindow.apertureCorner = i; + delete bestWindow.apertureDistances; + } + } + + } + + // actually re/move windows from/to assigned corners + for (var i = 0; i < stackingOrder.length; ++i) { + var w = stackingOrder[i]; + if (w.apertureCorner === undefined && w.offToCornerId === undefined) + continue; + + // keep windows above the desktop visually + effects.setElevatedWindow(w, showing); + + if (!showing && w.dock) { + cancel(w.offToCornerId); + delete w.offToCornerId; + delete w.apertureCorner; // should not exist, but better safe than sorry. + animate({ + window: w, + duration: badBadWindowsEffect.duration, + animations: [{ + type: Effect.Opacity, + from: 0.0 + }] + }); + continue; } - // calculate the closest corner var anchor, tx, ty; var geo = w.geometry; - if (screenGeo.x + screenGeo.width - geo.x < geo.x + geo.width - screenGeo.x) { + if (w.apertureCorner == 1 || w.apertureCorner == 2) { tx = screenGeo.x + screenGeo.width - xOffset; anchor = Effect.Left; } else { tx = xOffset; anchor = Effect.Right; } - if (screenGeo.y + screenGeo.height - geo.y < geo.y + geo.height - screenGeo.y) { + if (w.apertureCorner > 1) { ty = screenGeo.y + screenGeo.height - yOffset; anchor |= Effect.Top; } else { @@ -126,22 +175,24 @@ var badBadWindowsEffect = { } else { cancel(w.offToCornerId); delete w.offToCornerId; - animate({ - window: w, - duration: badBadWindowsEffect.duration, - curve: QEasingCurve.InOutQuad, - animations: [{ - type: Effect.Position, - sourceAnchor: anchor, - from: { value1: tx, value2: ty } - },{ - type: Effect.Opacity, - from: 0.2 - }] - }); + delete w.apertureCorner; + if (w.visible) { // could meanwhile have been hidden + animate({ + window: w, + duration: badBadWindowsEffect.duration, + curve: QEasingCurve.InOutQuad, + animations: [{ + type: Effect.Position, + sourceAnchor: anchor, + from: { value1: tx, value2: ty } + },{ + type: Effect.Opacity, + from: 0.2 + }] + }); + } } } - }, init: function () { "use strict";