1
/********************************************************************
2
KWin - the KDE window manager
3
This file is part of the KDE project.
5
Copyright (C) 2009 Nikhil Marathe <nsm.nikhil@gmail.com>
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program. If not, see <http://www.gnu.org/licenses/>.
19
*********************************************************************/
21
// all the tiling related code that is extensions to existing KWin classes
22
// Includes Workspace for now
25
#include "workspace.h"
27
#include "tilinglayout.h"
28
#include "tilinglayoutfactory.h"
30
#include <knotification.h>
32
#include <kwindowinfo.h>
33
#include <kwindowsystem.h>
39
bool Workspace::tilingEnabled() const
41
return tilingEnabled_;
44
void Workspace::setTilingEnabled(bool tiling)
46
if (tilingEnabled() == tiling) return;
48
tilingEnabled_ = tiling;
50
KSharedConfig::Ptr _config = KGlobal::config();
51
KConfigGroup config(_config, "Windows");
52
config.writeEntry("TilingOn", tilingEnabled_);
54
options->tilingOn = tilingEnabled_;
55
options->tilingLayout = static_cast<TilingLayoutFactory::Layouts>(config.readEntry("TilingDefaultLayout", 0));
56
options->tilingRaisePolicy = config.readEntry("TilingRaisePolicy", 0);
59
tilingLayouts.resize(numberOfDesktops() + 1);
60
foreach (Client * c, stackingOrder()) {
64
qDeleteAll(tilingLayouts);
65
tilingLayouts.clear();
69
void Workspace::slotToggleTiling()
71
if (tilingEnabled()) {
72
setTilingEnabled(false);
73
QString message = i18n("Tiling Disabled");
74
KNotification::event("tilingdisabled", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin"));
76
setTilingEnabled(true);
77
QString message = i18n("Tiling Enabled");
78
KNotification::event("tilingenabled", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin"));
82
void Workspace::createTile(Client *c)
87
if (c->desktop() < 0 || c->desktop() >= tilingLayouts.size()) return;
89
kDebug(1212) << "Now tiling " << c->caption();
90
if (!tilingEnabled() || !tileable(c))
93
Tile *t = new Tile(c, clientArea(PlacementArea, c));
95
kDebug(1212) << c->caption() << "is not tileable";
99
if (!tilingLayouts.value(c->desktop())) {
100
tilingLayouts[c->desktop()] = TilingLayoutFactory::createLayout(TilingLayoutFactory::DefaultLayout, this);
102
tilingLayouts[c->desktop()]->addTile(t);
103
tilingLayouts[c->desktop()]->commit();
106
void Workspace::removeTile(Client *c)
108
if (tilingLayouts[ c->desktop()])
109
tilingLayouts[ c->desktop()]->removeTile(c);
112
bool Workspace::tileable(Client *c)
115
kDebug(1212) << c->caption();
116
KWindowInfo info = KWindowSystem::windowInfo(c->window(), -1U, NET::WM2WindowClass);
117
kDebug(1212) << "WINDOW CLASS IS " << info.windowClassClass();
118
if (info.windowClassClass() == "Plasma-desktop") {
121
// TODO: if application specific settings
122
// to ignore, put them here
124
if (!c->isNormalWindow()) {
128
// 0 means tile it, if we get 1 (floating), don't tile
129
if (c->rules()->checkTilingOption(0) == 1) {
133
kDebug() << "Tiling" << c;
137
void Workspace::belowCursor()
142
Tile* Workspace::getNiceTile() const
144
if (!tilingEnabled()) return NULL;
145
if (!tilingLayouts.value(activeClient()->desktop())) return NULL;
147
return tilingLayouts[ activeClient()->desktop()]->findTile(activeClient());
151
void Workspace::updateAllTiles()
153
foreach (TilingLayout * t, tilingLayouts) {
160
* Resize the neighbouring clients to close any gaps
162
void Workspace::notifyTilingWindowResize(Client *c, const QRect &moveResizeGeom, const QRect &orig)
164
if (tilingLayouts.value(c->desktop()) == NULL)
166
tilingLayouts[ c->desktop()]->clientResized(c, moveResizeGeom, orig);
169
void Workspace::notifyTilingWindowMove(Client *c, const QRect &moveResizeGeom, const QRect &orig)
171
if (tilingLayouts.value(c->desktop()) == NULL) {
174
tilingLayouts[ c->desktop()]->clientMoved(c, moveResizeGeom, orig);
178
void Workspace::notifyTilingWindowResizeDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled)
181
notifyTilingWindowResize(c, orig, moveResizeGeom);
183
notifyTilingWindowResize(c, moveResizeGeom, orig);
186
void Workspace::notifyTilingWindowMoveDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled)
189
notifyTilingWindowMove(c, orig, moveResizeGeom);
191
notifyTilingWindowMove(c, moveResizeGeom, orig);
194
void Workspace::notifyTilingWindowDesktopChanged(Client *c, int old_desktop)
196
if (c->desktop() < 1 || c->desktop() > numberOfDesktops())
199
if (tilingLayouts.value(old_desktop)) {
200
Tile *t = tilingLayouts[ old_desktop ]->findTile(c);
202
// TODO: copied from createTile(), move this into separate method?
203
if (!tilingLayouts.value(c->desktop())) {
204
tilingLayouts[c->desktop()] = TilingLayoutFactory::createLayout(TilingLayoutFactory::DefaultLayout, this);
208
tilingLayouts[ c->desktop()]->addTile(t);
210
tilingLayouts[ old_desktop ]->removeTile(c);
211
tilingLayouts[ old_desktop ]->commit();
216
* Implements the 3 raising modes in Window Behaviour -> Advanced
218
void Workspace::notifyTilingWindowActivated(Client *c)
223
if (options->tilingRaisePolicy == 1) // individual raise/lowers
226
if (tilingLayouts.value(c->desktop())) {
227
QList<Tile *> tiles = tilingLayouts[ c->desktop()]->tiles();
229
StackingUpdatesBlocker blocker(this);
231
Tile *tile_to_raise = tilingLayouts[ c->desktop()]->findTile(c);
233
if (!tile_to_raise) {
237
kDebug(1212) << "FOUND TILE";
238
bool raise_floating = false;
239
if (options->tilingRaisePolicy == 2) // floating always on top
240
raise_floating = true;
242
raise_floating = tile_to_raise->floating();
244
foreach (Tile * t, tiles) {
245
if (t->floating() == raise_floating && t != tile_to_raise)
246
raiseClient(t->client());
248
// raise the current tile last so that it ends up on top
249
// but only if it supposed to be raised, required to support tilingRaisePolicy
250
kDebug(1212) << "Raise floating? " << raise_floating << "to raise is floating?" << tile_to_raise->floating();
251
if (tile_to_raise->floating() == raise_floating)
252
raiseClient(tile_to_raise->client());
256
void Workspace::notifyTilingWindowMinimizeToggled(Client *c)
258
if (tilingLayouts.value(c->desktop())) {
259
tilingLayouts[ c->desktop()]->clientMinimizeToggled(c);
263
void Workspace::notifyTilingWindowMaximized(Client *c, Options::WindowOperation op)
265
if (tilingLayouts.value(c->desktop())) {
266
Tile *t = tilingLayouts[ c->desktop()]->findTile(c);
269
t = tilingLayouts[ c->desktop()]->findTile(c);
271
// if still no tile, it couldn't be tiled
277
// if window IS tiled and a maximize
278
// is attempted, make the window float.
279
// That is all we do since that can
280
// mess up the layout.
281
// In all other cases, don't do
282
// anything, let the user manage toggling
285
&& (op == Options::MaximizeOp
286
|| op == Options::HMaximizeOp
287
|| op == Options::VMaximizeOp)) {
288
tilingLayouts[ c->desktop()]->toggleFloatTile(c);
294
Tile* Workspace::findAdjacentTile(Tile *ref, int d)
296
QRect reference = ref->geometry();
297
QPoint origin = reference.center();
299
Tile *closest = NULL;
302
QList<Tile *> tiles = tilingLayouts[ ref->client()->desktop()]->tiles();
304
foreach (Tile * t, tiles) {
305
if (t->client() == ref->client() || t->ignoreGeometry())
308
bool consider = false;
310
QRect other = t->geometry();
311
QPoint otherCenter = other.center();
315
consider = otherCenter.y() < origin.y()
316
&& other.bottom() < reference.top();
320
consider = otherCenter.x() > origin.x()
321
&& other.left() > reference.right();
325
consider = otherCenter.y() > origin.y()
326
&& other.top() > reference.bottom();
330
consider = otherCenter.x() < origin.x()
331
&& other.right() < reference.left();
339
int dist = (otherCenter - origin).manhattanLength();
340
if (minDist > dist || minDist < 0) {
349
void Workspace::focusTile(int d)
351
Tile *t = getNiceTile();
353
Tile *adj = findAdjacentTile(t, d);
355
activateClient(adj->client());
359
void Workspace::moveTile(int d)
361
Tile *t = getNiceTile();
363
Tile* adj = findAdjacentTile(t, d);
365
tilingLayouts[ t->client()->desktop()]->swapTiles(t, adj);
369
void Workspace::slotFocusTileLeft()
371
focusTile(Tile::Left);
374
void Workspace::slotFocusTileRight()
376
focusTile(Tile::Right);
379
void Workspace::slotFocusTileTop()
381
focusTile(Tile::Top);
384
void Workspace::slotFocusTileBottom()
386
focusTile(Tile::Bottom);
389
void Workspace::slotMoveTileLeft()
391
moveTile(Tile::Left);
394
void Workspace::slotMoveTileRight()
396
moveTile(Tile::Right);
399
void Workspace::slotMoveTileTop()
404
void Workspace::slotMoveTileBottom()
406
moveTile(Tile::Bottom);
409
void Workspace::slotToggleFloating()
411
Client *c = activeClient();
412
if (tilingLayouts.value(c->desktop())) {
413
tilingLayouts[ c->desktop()]->toggleFloatTile(c);
417
void Workspace::slotNextTileLayout()
419
if (tilingLayouts.value(currentDesktop())) {
421
tilingLayouts.replace(currentDesktop(), TilingLayoutFactory::nextLayout(tilingLayouts[currentDesktop()]));
423
tilingLayouts[currentDesktop()]->commit();
427
void Workspace::slotPreviousTileLayout()
429
if (tilingLayouts.value(currentDesktop())) {
431
tilingLayouts.replace(currentDesktop(), TilingLayoutFactory::previousLayout(tilingLayouts[currentDesktop()]));
433
tilingLayouts[currentDesktop()]->commit();
437
KDecorationDefines::Position Workspace::supportedTilingResizeMode(Client *c, KDecorationDefines::Position currentMode)
439
if (tilingLayouts.value(c->desktop())) {
440
return tilingLayouts[c->desktop()]->resizeMode(c, currentMode);
445
void Workspace::dumpTiles() const
447
foreach (TilingLayout * t, tilingLayouts) {
449
kDebug(1212) << "EMPTY DESKTOP";
452
kDebug(1212) << "Desktop" << tilingLayouts.indexOf(t);
453
foreach (Tile * tile, t->tiles()) {
454
tile->dumpTile("--");