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";