You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
204 lines
8.1 KiB
204 lines
8.1 KiB
/******************************************************************** |
|
KWin - the KDE window manager |
|
This file is part of the KDE project. |
|
|
|
Copyright (C) 2015 Thomas Lübking <thomas.luebking@gmail.com> |
|
|
|
This program is free software; you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation; either version 2 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
*********************************************************************/ |
|
/*global effect, effects, animate, animationTime, Effect, QEasingCurve */ |
|
|
|
var badBadWindowsEffect = { |
|
duration: animationTime(250), |
|
loadConfig: function () { |
|
"use strict"; |
|
badBadWindowsEffect.duration = animationTime(250); |
|
}, |
|
offToCorners: function (showing) { |
|
"use strict"; |
|
var stackingOrder = effects.stackingOrder; |
|
var screenGeo = effects.virtualScreenGeometry; |
|
var xOffset = screenGeo.width / 16; |
|
var yOffset = screenGeo.height / 16; |
|
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) |
|
break; |
|
|
|
// ignore invisible windows and such that do not have to be restored |
|
if (!w.visible) |
|
continue; |
|
|
|
// we just fade out docks - moving panels into edges looks dull |
|
if (w.dock) { |
|
w.offToCornerId = set({ |
|
window: w, |
|
duration: badBadWindowsEffect.duration, |
|
animations: [{ |
|
type: Effect.Opacity, |
|
to: 0.0 |
|
}] |
|
}); |
|
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; |
|
} |
|
|
|
var anchor, tx, ty; |
|
var geo = w.geometry; |
|
if (w.apertureCorner == 1 || w.apertureCorner == 2) { |
|
tx = screenGeo.x + screenGeo.width - xOffset; |
|
anchor = Effect.Left; |
|
} else { |
|
tx = xOffset; |
|
anchor = Effect.Right; |
|
} |
|
if (w.apertureCorner > 1) { |
|
ty = screenGeo.y + screenGeo.height - yOffset; |
|
anchor |= Effect.Top; |
|
} else { |
|
ty = yOffset; |
|
anchor |= Effect.Bottom; |
|
} |
|
|
|
if (showing) { |
|
w.offToCornerId = set({ |
|
window: w, |
|
duration: badBadWindowsEffect.duration, |
|
curve: QEasingCurve.InOutQuad, |
|
animations: [{ |
|
type: Effect.Position, |
|
targetAnchor: anchor, |
|
to: { value1: tx, value2: ty } |
|
},{ |
|
type: Effect.Opacity, |
|
to: 0.2 |
|
}] |
|
}); |
|
} else { |
|
cancel(w.offToCornerId); |
|
delete w.offToCornerId; |
|
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"; |
|
badBadWindowsEffect.loadConfig(); |
|
effects.showingDesktopChanged.connect(badBadWindowsEffect.offToCorners); |
|
} |
|
}; |
|
|
|
badBadWindowsEffect.init();
|
|
|