/******************************************************************** KWin - the KDE window manager This file is part of the KDE project. Copyright (C) 2012 Mathias Gottschlag <mgottschlag@gmail.com> Copyright (C) 2013-2014 Fabian Homborg <FHomborg@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/>. *********************************************************************/ /** * Class which implements tiling for a single screen. * @class */ function Tiling(layoutType, desktop, screen) { try { this.desktop = desktop; this.screen = screen; this.screenRectangle = util.getTilingArea(this.screen, this.desktop); /** * Tiles which have been added to the layout */ this.tiles = []; /** * Layout type which provided the current layout. */ this.layoutType = layoutType; /** * Layout which specifies window sizes/positions. */ this.layout = new layoutType(this.screenRectangle); /** * active: True if the layout is active (i.e. on the current desktop) * useractive: True if the layout is activated by the user * False if the user deactivated it * useractive implies active */ this.active = false; this.userActive = true; this.gapSize = readConfig("gapSize", 0); } catch(err) { print(err, "in Tiling"); } }; Tiling.prototype.setLayoutType = function(layoutType) { try { var newLayout = new layoutType(this.layout.screenRectangle); for (var i = 0; i < this.layout.tiles.length; i++) { newLayout.addTile(); } this.layout = newLayout; this.layoutType = layoutType; this._updateAllTiles(); } catch(err) { print(err, "in Tiling.setLayoutType"); } }; Tiling.prototype.addTile = function(tile, x, y) { try { this.layout.addTile(); // If a position was specified, we insert the tile at the specified position if (x != null && y != null) { var index = this._getTileIndex(x, y); if (index == -1) { this.tiles.push(tile); } else { this.tiles.splice(index, 0, tile); } } else { if (tile.tileIndex > -1) { this.tiles.splice(tile.tileIndex, 0, tile); } else { if (readConfig("startAsMaster", false) == true) { tile.tileIndex = 0; this.tiles.splice(tile.tileIndex, 0, tile); } else { tile.tileIndex = this.tiles.length; this.tiles.push(tile); } } for (var i = 0; i < this.tiles.length; i++) { this.tiles[i].tileIndex = i; this.tiles[i].syncCustomProperties(); } } this._updateAllTiles(); } catch(err) { print(err, "in Tiling.addTile"); } }; Tiling.prototype.removeTile = function(tile) { try { var tileIndex = this.tiles.indexOf(tile); if (tileIndex > -1) { this.tiles.splice(tileIndex, 1); this.layout.removeTile(tileIndex); // Correct tileIndex for (var i = 0; i < this.tiles.length; i++) { this.tiles[i].tileIndex = i; this.tiles[i].syncCustomProperties(); } // TODO: Unregister tile callbacks this._updateAllTiles(); } } catch(err) { print(err, "in Tiling.removeTile"); } }; Tiling.prototype.swapTiles = function(tile1, tile2) { try { // Cut down on updates by not doing them if tile1 is hovering over itself if (tile1 != tile2) { var index1 = this.tiles.indexOf(tile1); var index2 = this.tiles.indexOf(tile2); this.tiles[index1] = tile2; this.tiles[index2] = tile1; this.tiles[index1].tileIndex = index1; this.tiles[index2].tileIndex = index2; this.tiles[index1].syncCustomProperties(); this.tiles[index2].syncCustomProperties(); this._updateAllTiles(); // This will only be called if tile1 just stopped moving } else if (tile1._moving == false) { this._updateAllTiles(); } } catch(err) { print(err, "in Tiling.swapTiles"); } }; Tiling.prototype.activate = function() { if (this.userActive == true) { this.active = true; // Resize the tiles like specified by the layout this._updateAllTiles(); } }; Tiling.prototype.deactivate = function() { this.active = false; }; Tiling.prototype.toggleActive = function() { if (this.active) { this.deactivate(); } else { this.activate(); } }; Tiling.prototype.toggleUserActive = function() { if (this.userActive == true) { this.userActive = false; this.deactivate(); } else { this.userActive = true; this.activate(); } }; /** * Resets tile sizes to their initial size (in case they were resized by the * user). */ Tiling.prototype.resetTileSizes = function() { this.layout.resetTileSizes(); this._updateAllTiles(); }; Tiling.prototype.getTile = function(x, y) { try { var index = this._getTileIndex(x, y); if (index != -1) { return this.tiles[index]; } else { return null; } } catch(err) { print(err, "in Tiling.getTile"); } }; Tiling.prototype._getTileIndex = function(x, y) { try { for (var i = 0; i < this.layout.tiles.length; i++) { var tile = this.layout.tiles[i]; if (tile.rectangle.x <= x && tile.rectangle.y <= y && tile.rectangle.x + tile.rectangle.width > x && tile.rectangle.y + tile.rectangle.height > y) { return i; } } return -1; } catch(err) { print(err, "in Tiling._getTileIndex"); } }; Tiling.prototype.resizeTile = function(tile){ try { if (tile != null) { var tileIndex = tile.tileIndex; var client = tile.clients[0]; this.layout.resizeTile(tileIndex, client.geometry); this._updateAllTiles(); } } catch(err) { print(err, "in Tiling.resizeTile"); } }; Tiling.prototype.resizeTileTo = function(tile,geometry) { try { if (tile != null && geometry != null) { var tileIndex = tile.tileIndex; var client = tile.clients[0]; this.layout.resizeTile(tileIndex, geometry); this._updateAllTiles(); } } catch(err) { print(err, "in Tiling.resizeTileTo"); } } Tiling.prototype._updateAllTiles = function() { try { // Set the position/size of all tiles if (this.active == true && this.userActive == true) { this.resizeScreen(); for (var i = 0; i < this.layout.tiles.length; i++) { var newRect = this.layout.tiles[i].rectangle; if (! newRect) { return; } var geometry = Qt.rect(newRect.x + this.gapSize, newRect.y + this.gapSize, newRect.width - (this.gapSize * 2), newRect.height - (this.gapSize * 2)); if (geometry.x < this.screenRectangle.x || geometry.x == this.screenRectangle.x + this.gapSize) { geometry.x = this.screenRectangle.x; geometry.width = geometry.width + this.gapSize; } if (geometry.x + geometry.width + this.gapSize * 2 >= this.screenRectangle.x + this.screenRectangle.width) { geometry.width = this.screenRectangle.x + this.screenRectangle.width - geometry.x; } if (geometry.y < this.screenRectangle.y || geometry.y == this.screenRectangle.y + this.gapSize) { geometry.y = this.screenRectangle.y; geometry.height = geometry.height + this.gapSize; } if (geometry.y + geometry.height + this.gapSize * 2 >= this.screenRectangle.y + this.screenRectangle.height) { geometry.height = this.screenRectangle.y + this.screenRectangle.height - geometry.y; } this.tiles[i].setGeometry(geometry); } } } catch(err) { print(err, "in Tiling._updateAllTiles"); } }; Tiling.prototype.resizeMaster = function(geometry) { try { if (this.layout.master > -1) { this.layout.resizeTile(this.layout.master, geometry); this._updateAllTiles(); } } catch(err) { print(err, "in resizeMaster"); } }; Tiling.prototype.getMaster = function() { if (this.layout.master > -1) { return this.tiles[this.layout.master]; } else { return null; } }; Tiling.prototype.resizeScreen = function() { // FIXME: KWin bug: clientArea returns the _former_ area // See https://bugs.kde.org/show_bug.cgi?id=330099 var rect = util.getTilingArea(this.screen, this.desktop); if (util.compareRect(rect,this.screenRectangle) == false) { this.layout.screenRectangle.x = this.screenRectangle.x; this.layout.screenRectangle.y = this.screenRectangle.y; this.layout.screenRectangle.width = this.screenRectangle.width; this.layout.screenRectangle.height = this.screenRectangle.height; this.layout.setLayoutArea(rect); this.screenRectangle = rect; } }; Tiling.prototype.tile = function() { this.tiles.forEach(function(tile) { tile.setGeometry(tile.rectangle); }); }; Tiling.prototype.increaseMaster = function() { if (this.layout.increaseMaster != null) { this.layout.increaseMaster(); this._updateAllTiles(); } }; Tiling.prototype.decrementMaster = function() { if (this.layout.decrementMaster != null) { this.layout.decrementMaster(); this._updateAllTiles(); } };