diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ef13e59cd..7efb982392 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,6 +4,7 @@ OPTION(KWIN_BUILD_DECORATIONS "Enable building of KWin decorations." ON) OPTION(KWIN_BUILD_KCMS "Enable building of KWin configuration modules." ON) OPTION(KWIN_MOBILE_EFFECTS "Only build effects relevant for mobile devices" OFF) OPTION(KWIN_BUILD_TABBOX "Enable building of KWin Tabbox functionality" ON) +OPTION(KWIN_BUILD_TILING "Enable building of KWin Tiling functionality" ON) OPTION(KWIN_BUILD_DESKTOPCHANGEOSD "Enable building of KWin DesktopChangeOSD funtionality" ON) OPTION(KWIN_BUILD_SCREENEDGES "Enable building of KWin with screen edge support" ON) OPTION(KWIN_BUILD_SCRIPTING "Enable building of KWin with scripting support" ON) @@ -18,6 +19,7 @@ if(KWIN_PLASMA_ACTIVE) set(KWIN_BUILD_DECORATIONS OFF) set(KWIN_BUILD_KCMS OFF) set(KWIN_BUILD_TABBOX OFF) + set(KWIN_BUILD_TILING OFF) set(KWIN_BUILD_DESKTOPCHANGEOSD OFF) set(KWIN_BUILD_SCREENEDGES OFF) set(KWIN_BUILD_SCRIPTING OFF) @@ -144,22 +146,6 @@ set(kwin_KDEINIT_SRCS compositingprefs.cpp desktoplayout.cpp paintredirector.cpp - tile.cpp - tiling.cpp - tilinglayout.cpp - tilinglayoutfactory.cpp - - # tiling layouts - # spiral - #tilinglayouts/spiral/spiralfactory.cpp - tilinglayouts/spiral/spiral.cpp - - # columns - #tilinglayouts/columns/columnsfactory.cpp - tilinglayouts/columns/columns.cpp - - # floating - tilinglayouts/floating/floating.cpp ) if(KWIN_BUILD_SCRIPTING) @@ -193,6 +179,26 @@ if(KWIN_BUILD_TABBOX) ) endif(KWIN_BUILD_TABBOX) +if(KWIN_BUILD_TILING) + set( + kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} + tiling/tile.cpp + tiling/tiling.cpp + tiling/tilinglayout.cpp + tilinglayoutfactory.cpp + + # tiling layouts + # spiral + tilinglayouts/spiral/spiral.cpp + + # columns + tilinglayouts/columns/columns.cpp + + # floating + tilinglayouts/floating/floating.cpp + ) +endif(KWIN_BUILD_TILING) + if(KWIN_BUILD_DESKTOPCHANGEOSD) set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} desktopchangeosd.cpp diff --git a/activation.cpp b/activation.cpp index 1f67f96a42..911e9e65c8 100644 --- a/activation.cpp +++ b/activation.cpp @@ -262,9 +262,6 @@ void Workspace::setActiveClient(Client* c, allowed_t) if (active_client) { active_client->sl_activated(); } - - if (tilingEnabled()) - notifyTilingWindowActivated(active_client); --set_active_client_recursion; } diff --git a/client.cpp b/client.cpp index c4fdd95d87..46c8effed8 100644 --- a/client.cpp +++ b/client.cpp @@ -950,9 +950,6 @@ void Client::minimize(bool avoid_animation) // TODO: merge signal with s_minimized emit clientMinimized(this, !avoid_animation); - // when tiling, request a rearrangement - workspace()->notifyTilingWindowMinimizeToggled(this); - // Update states of all other windows in this group if (clientGroup()) clientGroup()->updateStates(this); @@ -978,12 +975,8 @@ void Client::unminimize(bool avoid_animation) updateAllowedActions(); workspace()->updateMinimizedOfTransients(this); updateWindowRules(); - workspace()->updateAllTiles(); emit clientUnminimized(this, !avoid_animation); - // when tiling, request a rearrangement - workspace()->notifyTilingWindowMinimizeToggled(this); - // Update states of all other windows in this group if (clientGroup()) clientGroup()->updateStates(this); diff --git a/config-kwin.h.cmake b/config-kwin.h.cmake index 8c8c9d9011..b5bd9b6f08 100644 --- a/config-kwin.h.cmake +++ b/config-kwin.h.cmake @@ -2,6 +2,7 @@ #cmakedefine HAVE_CAPTURY 1 #cmakedefine KWIN_BUILD_DECORATIONS 1 #cmakedefine KWIN_BUILD_TABBOX 1 +#cmakedefine KWIN_BUILD_TILING 1 #cmakedefine KWIN_BUILD_DESKTOPCHANGEOSD 1 #cmakedefine KWIN_BUILD_SCREENEDGES 1 #cmakedefine KWIN_BUILD_SCRIPTING 1 diff --git a/geometry.cpp b/geometry.cpp index a357162b15..af6ce8c50c 100644 --- a/geometry.cpp +++ b/geometry.cpp @@ -50,6 +50,9 @@ along with this program. If not, see . #include #include #include "outline.h" +#ifdef KWIN_BUILD_TILING +#include "tiling/tiling.h" +#endif namespace KWin { @@ -2032,7 +2035,9 @@ void Client::move(int x, int y, ForceGeometry_t force) workspace()->checkActiveScreen(this); workspace()->updateStackingOrder(); workspace()->checkUnredirect(); - workspace()->notifyTilingWindowMove(this, moveResizeGeom, initialMoveResizeGeom); +#ifdef KWIN_BUILD_TILING + workspace()->tiling()->notifyTilingWindowMove(this, moveResizeGeom, initialMoveResizeGeom); +#endif // client itself is not damaged const QRect deco_rect = decorationRect().translated(geom.x(), geom.y()); addWorkspaceRepaint(deco_rect_before_block); @@ -2590,17 +2595,26 @@ void Client::finishMoveResize(bool cancel) leaveMoveResize(); - if (workspace()->tilingEnabled()) { +#ifdef KWIN_BUILD_TILING + if (workspace()->tiling()->isEnabled()) { if (wasResize) - workspace()->notifyTilingWindowResizeDone(this, moveResizeGeom, initialMoveResizeGeom, cancel); + workspace()->tiling()->notifyTilingWindowResizeDone(this, moveResizeGeom, initialMoveResizeGeom, cancel); else if (wasMove) - workspace()->notifyTilingWindowMoveDone(this, moveResizeGeom, initialMoveResizeGeom, cancel); + workspace()->tiling()->notifyTilingWindowMoveDone(this, moveResizeGeom, initialMoveResizeGeom, cancel); } else { if (cancel) setGeometry(initialMoveResizeGeom); else setGeometry(moveResizeGeom); } +#else + if (cancel) + setGeometry(initialMoveResizeGeom); + else + setGeometry(moveResizeGeom); + Q_UNUSED(wasResize); + Q_UNUSED(wasMove); +#endif if (cancel) setGeometry(initialMoveResizeGeom); @@ -2762,10 +2776,12 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) bool update = false; if (isResize()) { +#ifdef KWIN_BUILD_TILING // query layout for supported resize mode - if (workspace()->tilingEnabled()) { - mode = workspace()->supportedTilingResizeMode(this, mode); + if (workspace()->tiling()->isEnabled()) { + mode = workspace()->tiling()->supportedTilingResizeMode(this, mode); } +#endif // first resize (without checking constrains), then snap, then check bounds, then check constrains QRect orig = initialMoveResizeGeom; Sizemode sizemode = SizemodeAny; @@ -2799,18 +2815,22 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) sizemode = SizemodeFixedW; break; case PositionCenter: +#ifdef KWIN_BUILD_TILING // exception for tiling // Center means no resizing allowed - if (workspace()->tilingEnabled()) { + if (workspace()->tiling()->isEnabled()) { finishMoveResize(false); buttonDown = false; return; } +#endif default: abort(); break; } - workspace()->notifyTilingWindowResize(this, moveResizeGeom, initialMoveResizeGeom); +#ifdef KWIN_BUILD_TILING + workspace()->tiling()->notifyTilingWindowResize(this, moveResizeGeom, initialMoveResizeGeom); +#endif // adjust new size to snap to other windows/borders moveResizeGeom = workspace()->adjustClientSize(this, moveResizeGeom, mode); @@ -2968,7 +2988,9 @@ void Client::handleMoveResize(int x, int y, int x_root, int y_root) performMoveResize(); if (isMove()) { - workspace()->notifyTilingWindowMove(this, moveResizeGeom, initialMoveResizeGeom); +#ifdef KWIN_BUILD_TILING + workspace()->tiling()->notifyTilingWindowMove(this, moveResizeGeom, initialMoveResizeGeom); +#endif #ifdef KWIN_BUILD_SCREENEDGES workspace()->screenEdge()->check(globalPos, xTime()); #endif @@ -2986,8 +3008,10 @@ void Client::performMoveResize() sendSyncRequest(); } #endif - if (!workspace()->tilingEnabled()) +#ifdef KWIN_BUILD_TILING + if (!workspace()->tiling()->isEnabled()) setGeometry(moveResizeGeom); +#endif positionGeometryTip(); emit clientStepUserMovedResized(this, moveResizeGeom); } diff --git a/kwinbindings.cpp b/kwinbindings.cpp index 0d818570e6..0bea892be5 100644 --- a/kwinbindings.cpp +++ b/kwinbindings.cpp @@ -188,22 +188,6 @@ DEF(I18N_NOOP("Kill Window"), Qt::CTRL + Qt::ALT + Qt::Key_ DEF(I18N_NOOP("Block Global Shortcuts"), 0, slotDisableGlobalShortcuts()); DEF(I18N_NOOP("Suspend Compositing"), Qt::SHIFT + Qt::ALT + Qt::Key_F12, slotToggleCompositing()); -a = actionCollection->addAction("Group:Tiling"); -a->setText(i18n("Tiling")); -DEF(I18N_NOOP("Enable/Disable Tiling"), Qt::SHIFT + Qt::ALT + Qt::Key_F11, slotToggleTiling()); -DEF(I18N_NOOP("Toggle Floating"), Qt::META + Qt::Key_F, slotToggleFloating()); - -DEF(I18N_NOOP("Switch Focus Left") , Qt::META + Qt::Key_H, slotFocusTileLeft()); -DEF(I18N_NOOP("Switch Focus Right") , Qt::META + Qt::Key_L, slotFocusTileRight()); -DEF(I18N_NOOP("Switch Focus Up") , Qt::META + Qt::Key_K, slotFocusTileTop()); -DEF(I18N_NOOP("Switch Focus Down") , Qt::META + Qt::Key_J, slotFocusTileBottom()); -DEF(I18N_NOOP("Move Window Left") , Qt::SHIFT + Qt::META + Qt::Key_H, slotMoveTileLeft()); -DEF(I18N_NOOP("Move Window Right") , Qt::SHIFT + Qt::META + Qt::Key_L, slotMoveTileRight()); -DEF(I18N_NOOP("Move Window Up") , Qt::SHIFT + Qt::META + Qt::Key_K, slotMoveTileTop()); -DEF(I18N_NOOP("Move Window Down") , Qt::SHIFT + Qt::META + Qt::Key_J, slotMoveTileBottom()); -DEF(I18N_NOOP("Next Layout"), Qt::META + Qt::Key_PageDown, slotNextTileLayout()); -DEF(I18N_NOOP("Previous Layout"), Qt::META + Qt::Key_PageUp, slotPreviousTileLayout()); - #undef DEF #undef DEF2 diff --git a/sm.cpp b/sm.cpp index db44ce008d..113018cdf3 100644 --- a/sm.cpp +++ b/sm.cpp @@ -34,6 +34,9 @@ along with this program. If not, see . #include #include #include +#ifdef KWIN_BUILD_TILING +#include "tiling/tiling.h" +#endif namespace KWin { @@ -84,11 +87,13 @@ void Workspace::storeSession(KConfig* config, SMSavePhase phase) int active_client = -1; if (phase == SMSavePhase2 || phase == SMSavePhase2Full) { - cg.writeEntry("tiling", tilingEnabled()); - if (tilingEnabled()) { +#ifdef KWIN_BUILD_TILING + cg.writeEntry("tiling", m_tiling->isEnabled()); + if (m_tiling->isEnabled()) { kDebug(1212) << "Tiling was ON"; - setTilingEnabled(false); + m_tiling->setEnabled(false); } +#endif } for (ClientList::Iterator it = clients.begin(); it != clients.end(); ++it) { @@ -273,7 +278,9 @@ void Workspace::loadSessionInfo() session.clear(); KConfigGroup cg(kapp->sessionConfig(), "Session"); - setTilingEnabled(cg.readEntry("tiling", false)); +#ifdef KWIN_BUILD_TILING + m_tiling->setEnabled(cg.readEntry("tiling", false)); +#endif addSessionInfo(cg); } diff --git a/tiling.cpp b/tiling.cpp deleted file mode 100644 index 85b22274db..0000000000 --- a/tiling.cpp +++ /dev/null @@ -1,459 +0,0 @@ -/******************************************************************** - KWin - the KDE window manager - This file is part of the KDE project. - -Copyright (C) 2009 Nikhil Marathe - -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 . -*********************************************************************/ - -// all the tiling related code that is extensions to existing KWin classes -// Includes Workspace for now - -#include "client.h" -#include "workspace.h" -#include "tile.h" -#include "tilinglayout.h" -#include "tilinglayoutfactory.h" - -#include -#include -#include -#include - - -namespace KWin -{ - -bool Workspace::tilingEnabled() const -{ - return tilingEnabled_; -} - -void Workspace::setTilingEnabled(bool tiling) -{ - if (tilingEnabled() == tiling) return; - - tilingEnabled_ = tiling; - - KSharedConfig::Ptr _config = KGlobal::config(); - KConfigGroup config(_config, "Windows"); - config.writeEntry("TilingOn", tilingEnabled_); - config.sync(); - options->tilingOn = tilingEnabled_; - options->tilingLayout = static_cast(config.readEntry("TilingDefaultLayout", 0)); - options->tilingRaisePolicy = config.readEntry("TilingRaisePolicy", 0); - - if (tilingEnabled_) { - tilingLayouts.resize(numberOfDesktops() + 1); - foreach (Client * c, stackingOrder()) { - createTile(c); - } - } else { - qDeleteAll(tilingLayouts); - tilingLayouts.clear(); - } -} - -void Workspace::slotToggleTiling() -{ - if (tilingEnabled()) { - setTilingEnabled(false); - QString message = i18n("Tiling Disabled"); - KNotification::event("tilingdisabled", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin")); - } else { - setTilingEnabled(true); - QString message = i18n("Tiling Enabled"); - KNotification::event("tilingenabled", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin")); - } -} - -void Workspace::createTile(Client *c) -{ - if (c == NULL) - return; - - if (c->desktop() < 0 || c->desktop() >= tilingLayouts.size()) return; - - kDebug(1212) << "Now tiling " << c->caption(); - if (!tilingEnabled() || !tileable(c)) - return; - - Tile *t = new Tile(c, clientArea(PlacementArea, c)); - if (!tileable(c)) { - kDebug(1212) << c->caption() << "is not tileable"; - t->floatTile(); - } - - if (!tilingLayouts.value(c->desktop())) { - tilingLayouts[c->desktop()] = TilingLayoutFactory::createLayout(TilingLayoutFactory::DefaultLayout, this); - } - tilingLayouts[c->desktop()]->addTile(t); - tilingLayouts[c->desktop()]->commit(); -} - -void Workspace::removeTile(Client *c) -{ - if (tilingLayouts[ c->desktop()]) - tilingLayouts[ c->desktop()]->removeTile(c); -} - -bool Workspace::tileable(Client *c) -{ - - kDebug(1212) << c->caption(); - KWindowInfo info = KWindowSystem::windowInfo(c->window(), -1U, NET::WM2WindowClass); - kDebug(1212) << "WINDOW CLASS IS " << info.windowClassClass(); - if (info.windowClassClass() == "Plasma-desktop") { - return false; - } - // TODO: if application specific settings - // to ignore, put them here - - if (!c->isNormalWindow()) { - return false; - } - - // 0 means tile it, if we get 1 (floating), don't tile - if (c->rules()->checkTilingOption(0) == 1) { - return false; - } - - kDebug() << "Tiling" << c; - return true; -} - -void Workspace::belowCursor() -{ - // TODO -} - -Tile* Workspace::getNiceTile() const -{ - if (!tilingEnabled()) return NULL; - if (!tilingLayouts.value(activeClient()->desktop())) return NULL; - - return tilingLayouts[ activeClient()->desktop()]->findTile(activeClient()); - // TODO -} - -void Workspace::updateAllTiles() -{ - foreach (TilingLayout * t, tilingLayouts) { - if (!t) continue; - t->commit(); - } -} - -/* - * Resize the neighbouring clients to close any gaps - */ -void Workspace::notifyTilingWindowResize(Client *c, const QRect &moveResizeGeom, const QRect &orig) -{ - if (tilingLayouts.value(c->desktop()) == NULL) - return; - tilingLayouts[ c->desktop()]->clientResized(c, moveResizeGeom, orig); -} - -void Workspace::notifyTilingWindowMove(Client *c, const QRect &moveResizeGeom, const QRect &orig) -{ - if (tilingLayouts.value(c->desktop()) == NULL) { - return; - } - tilingLayouts[ c->desktop()]->clientMoved(c, moveResizeGeom, orig); - updateAllTiles(); -} - -void Workspace::notifyTilingWindowResizeDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled) -{ - if (canceled) - notifyTilingWindowResize(c, orig, moveResizeGeom); - else - notifyTilingWindowResize(c, moveResizeGeom, orig); -} - -void Workspace::notifyTilingWindowMoveDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled) -{ - if (canceled) - notifyTilingWindowMove(c, orig, moveResizeGeom); - else - notifyTilingWindowMove(c, moveResizeGeom, orig); -} - -void Workspace::notifyTilingWindowDesktopChanged(Client *c, int old_desktop) -{ - if (c->desktop() < 1 || c->desktop() > numberOfDesktops()) - return; - - if (tilingLayouts.value(old_desktop)) { - Tile *t = tilingLayouts[ old_desktop ]->findTile(c); - - // TODO: copied from createTile(), move this into separate method? - if (!tilingLayouts.value(c->desktop())) { - tilingLayouts[c->desktop()] = TilingLayoutFactory::createLayout(TilingLayoutFactory::DefaultLayout, this); - } - - if (t) - tilingLayouts[ c->desktop()]->addTile(t); - - tilingLayouts[ old_desktop ]->removeTile(c); - tilingLayouts[ old_desktop ]->commit(); - } -} - -/* - * Implements the 3 raising modes in Window Behaviour -> Advanced - */ -void Workspace::notifyTilingWindowActivated(Client *c) -{ - if (c == NULL) - return; - - if (options->tilingRaisePolicy == 1) // individual raise/lowers - return; - - if (tilingLayouts.value(c->desktop())) { - QList tiles = tilingLayouts[ c->desktop()]->tiles(); - - StackingUpdatesBlocker blocker(this); - - Tile *tile_to_raise = tilingLayouts[ c->desktop()]->findTile(c); - - if (!tile_to_raise) { - return; - } - - kDebug(1212) << "FOUND TILE"; - bool raise_floating = false; - if (options->tilingRaisePolicy == 2) // floating always on top - raise_floating = true; - else - raise_floating = tile_to_raise->floating(); - - foreach (Tile * t, tiles) { - if (t->floating() == raise_floating && t != tile_to_raise) - raiseClient(t->client()); - } - // raise the current tile last so that it ends up on top - // but only if it supposed to be raised, required to support tilingRaisePolicy - kDebug(1212) << "Raise floating? " << raise_floating << "to raise is floating?" << tile_to_raise->floating(); - if (tile_to_raise->floating() == raise_floating) - raiseClient(tile_to_raise->client()); - } -} - -void Workspace::notifyTilingWindowMinimizeToggled(Client *c) -{ - if (tilingLayouts.value(c->desktop())) { - tilingLayouts[ c->desktop()]->clientMinimizeToggled(c); - } -} - -void Workspace::notifyTilingWindowMaximized(Client *c, Options::WindowOperation op) -{ - if (tilingLayouts.value(c->desktop())) { - Tile *t = tilingLayouts[ c->desktop()]->findTile(c); - if (!t) { - createTile(c); - t = tilingLayouts[ c->desktop()]->findTile(c); - - // if still no tile, it couldn't be tiled - // so ignore it - if (!t) - return; - } - - // if window IS tiled and a maximize - // is attempted, make the window float. - // That is all we do since that can - // mess up the layout. - // In all other cases, don't do - // anything, let the user manage toggling - // using Meta+F - if (!t->floating() - && (op == Options::MaximizeOp - || op == Options::HMaximizeOp - || op == Options::VMaximizeOp)) { - tilingLayouts[ c->desktop()]->toggleFloatTile(c); - } - - } -} - -Tile* Workspace::findAdjacentTile(Tile *ref, int d) -{ - QRect reference = ref->geometry(); - QPoint origin = reference.center(); - - Tile *closest = NULL; - int minDist = -1; - - QList tiles = tilingLayouts[ ref->client()->desktop()]->tiles(); - - foreach (Tile * t, tiles) { - if (t->client() == ref->client() || t->ignoreGeometry()) - continue; - - bool consider = false; - - QRect other = t->geometry(); - QPoint otherCenter = other.center(); - - switch(d) { - case Tile::Top: - consider = otherCenter.y() < origin.y() - && other.bottom() < reference.top(); - break; - - case Tile::Right: - consider = otherCenter.x() > origin.x() - && other.left() > reference.right(); - break; - - case Tile::Bottom: - consider = otherCenter.y() > origin.y() - && other.top() > reference.bottom(); - break; - - case Tile::Left: - consider = otherCenter.x() < origin.x() - && other.right() < reference.left(); - break; - - default: - abort(); - } - - if (consider) { - int dist = (otherCenter - origin).manhattanLength(); - if (minDist > dist || minDist < 0) { - minDist = dist; - closest = t; - } - } - } - return closest; -} - -void Workspace::focusTile(int d) -{ - Tile *t = getNiceTile(); - if (t) { - Tile *adj = findAdjacentTile(t, d); - if (adj) - activateClient(adj->client()); - } -} - -void Workspace::moveTile(int d) -{ - Tile *t = getNiceTile(); - if (t) { - Tile* adj = findAdjacentTile(t, d); - - tilingLayouts[ t->client()->desktop()]->swapTiles(t, adj); - } -} - -void Workspace::slotFocusTileLeft() -{ - focusTile(Tile::Left); -} - -void Workspace::slotFocusTileRight() -{ - focusTile(Tile::Right); -} - -void Workspace::slotFocusTileTop() -{ - focusTile(Tile::Top); -} - -void Workspace::slotFocusTileBottom() -{ - focusTile(Tile::Bottom); -} - -void Workspace::slotMoveTileLeft() -{ - moveTile(Tile::Left); -} - -void Workspace::slotMoveTileRight() -{ - moveTile(Tile::Right); -} - -void Workspace::slotMoveTileTop() -{ - moveTile(Tile::Top); -} - -void Workspace::slotMoveTileBottom() -{ - moveTile(Tile::Bottom); -} - -void Workspace::slotToggleFloating() -{ - Client *c = activeClient(); - if (tilingLayouts.value(c->desktop())) { - tilingLayouts[ c->desktop()]->toggleFloatTile(c); - } -} - -void Workspace::slotNextTileLayout() -{ - if (tilingLayouts.value(currentDesktop())) { - - tilingLayouts.replace(currentDesktop(), TilingLayoutFactory::nextLayout(tilingLayouts[currentDesktop()])); - - tilingLayouts[currentDesktop()]->commit(); - } -} - -void Workspace::slotPreviousTileLayout() -{ - if (tilingLayouts.value(currentDesktop())) { - - tilingLayouts.replace(currentDesktop(), TilingLayoutFactory::previousLayout(tilingLayouts[currentDesktop()])); - - tilingLayouts[currentDesktop()]->commit(); - } -} - -KDecorationDefines::Position Workspace::supportedTilingResizeMode(Client *c, KDecorationDefines::Position currentMode) -{ - if (tilingLayouts.value(c->desktop())) { - return tilingLayouts[c->desktop()]->resizeMode(c, currentMode); - } - return currentMode; -} - -void Workspace::dumpTiles() const -{ - foreach (TilingLayout * t, tilingLayouts) { - if (!t) { - kDebug(1212) << "EMPTY DESKTOP"; - continue; - } - kDebug(1212) << "Desktop" << tilingLayouts.indexOf(t); - foreach (Tile * tile, t->tiles()) { - tile->dumpTile("--"); - } - } -} -} // namespace - diff --git a/tile.cpp b/tiling/tile.cpp similarity index 97% rename from tile.cpp rename to tiling/tile.cpp index a188129581..ee1f848a09 100644 --- a/tile.cpp +++ b/tiling/tile.cpp @@ -26,6 +26,7 @@ along with this program. If not, see . #include "client.h" #include "workspace.h" +#include "tiling/tiling.h" namespace KWin { @@ -95,7 +96,7 @@ void Tile::floatTile() restorePreviousGeometry(); commit(); - client()->workspace()->notifyTilingWindowActivated(client()); + client()->workspace()->tiling()->notifyTilingWindowActivated(client()); // TODO: notify layout manager } diff --git a/tile.h b/tiling/tile.h similarity index 100% rename from tile.h rename to tiling/tile.h diff --git a/tiling/tiling.cpp b/tiling/tiling.cpp new file mode 100644 index 0000000000..0b8fb95e66 --- /dev/null +++ b/tiling/tiling.cpp @@ -0,0 +1,520 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Nikhil Marathe +Copyright (C) 2011 Arthur Arlt + +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 . +*********************************************************************/ + +#include + +#include +#include +#include +#include + +#include +#include + +#include "tiling/tile.h" +#include "tiling/tilinglayout.h" +#include "tilinglayoutfactory.h" +#include "workspace.h" + +namespace KWin { +Tiling::Tiling(KWin::Workspace* w) + : QObject(w) + , m_workspace(w) + , m_enabled(false) +{ +} + +Tiling::~Tiling() +{ +} + +void Tiling::initShortcuts(KActionCollection* keys){ + KAction *a = NULL; + #define KEY( name, key, fnSlot ) \ + a = keys->addAction( name ); \ + a->setText( i18n( name ) ); \ + qobject_cast( a )->setGlobalShortcut(KShortcut(key)); \ + connect(a, SIGNAL(triggered(bool)), SLOT(fnSlot)); + + a = keys->addAction("Group:Tiling"); + a->setText(i18n("Tiling")); + KEY(I18N_NOOP("Enable/Disable Tiling"), Qt::SHIFT + Qt::ALT + Qt::Key_F11, slotToggleTiling()); + KEY(I18N_NOOP("Toggle Floating"), Qt::META + Qt::Key_F, slotToggleFloating()); + + KEY(I18N_NOOP("Switch Focus Left") , Qt::META + Qt::Key_H, slotFocusTileLeft()); + KEY(I18N_NOOP("Switch Focus Right") , Qt::META + Qt::Key_L, slotFocusTileRight()); + KEY(I18N_NOOP("Switch Focus Up") , Qt::META + Qt::Key_K, slotFocusTileTop()); + KEY(I18N_NOOP("Switch Focus Down") , Qt::META + Qt::Key_J, slotFocusTileBottom()); + KEY(I18N_NOOP("Move Window Left") , Qt::SHIFT + Qt::META + Qt::Key_H, slotMoveTileLeft()); + KEY(I18N_NOOP("Move Window Right") , Qt::SHIFT + Qt::META + Qt::Key_L, slotMoveTileRight()); + KEY(I18N_NOOP("Move Window Up") , Qt::SHIFT + Qt::META + Qt::Key_K, slotMoveTileTop()); + KEY(I18N_NOOP("Move Window Down") , Qt::SHIFT + Qt::META + Qt::Key_J, slotMoveTileBottom()); + KEY(I18N_NOOP("Next Layout"), Qt::META + Qt::Key_PageDown, slotNextTileLayout()); + KEY(I18N_NOOP("Previous Layout"), Qt::META + Qt::Key_PageUp, slotPreviousTileLayout()); + +} + +bool Tiling::isEnabled() const +{ + return m_enabled; +} + +void Tiling::setEnabled(bool tiling) +{ + if (isEnabled() == tiling) return; + + m_enabled = tiling; + + KSharedConfig::Ptr _config = KGlobal::config(); + KConfigGroup config(_config, "Windows"); + config.writeEntry("TilingOn", m_enabled); + config.sync(); + options->tilingOn = m_enabled; + options->tilingLayout = static_cast(config.readEntry("TilingDefaultLayout", 0)); + options->tilingRaisePolicy = config.readEntry("TilingRaisePolicy", 0); + + if (m_enabled) { + connect(m_workspace, SIGNAL(clientAdded(KWin::Client*)), this, SLOT(createTile(KWin::Client*))); + connect(m_workspace, SIGNAL(clientAdded(KWin::Client*)), this, SLOT(slotResizeTilingLayouts())); + connect(m_workspace, SIGNAL(numberDesktopsChanged(int)), this, SLOT(slotResizeTilingLayouts())); + connect(m_workspace, SIGNAL(clientRemoved(KWin::Client*)), this, SLOT(removeTile(KWin::Client*))); + connect(m_workspace, SIGNAL(clientActivated(KWin::Client*)), this, SLOT(notifyTilingWindowActivated(KWin::Client*))); + m_tilingLayouts.resize(Workspace::self()->numberOfDesktops() + 1); + foreach (Client * c, Workspace::self()->stackingOrder()) { + createTile(c); + } + } else { + disconnect(m_workspace, SIGNAL(clientAdded(KWin::Client*))); + disconnect(m_workspace, SIGNAL(numberDesktopsChanged(int))); + disconnect(m_workspace, SIGNAL(clientRemoved(KWin::Client*))); + qDeleteAll(m_tilingLayouts); + m_tilingLayouts.clear(); + } +} + +void Tiling::slotToggleTiling() +{ + if (isEnabled()) { + setEnabled(false); + QString message = i18n("Tiling Disabled"); + KNotification::event("tilingdisabled", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin")); + } else { + setEnabled(true); + QString message = i18n("Tiling Enabled"); + KNotification::event("tilingenabled", message, QPixmap(), NULL, KNotification::CloseOnTimeout, KComponentData("kwin")); + } +} + +void Tiling::createTile(Client* c) +{ + if (c == NULL) + return; + + if (c->desktop() < 0 || c->desktop() >= m_tilingLayouts.size()) return; + + kDebug(1212) << "Now tiling " << c->caption(); + if (!isEnabled() || !tileable(c)) + return; + + Tile *t = new Tile(c, Workspace::self()->clientArea(PlacementArea, c)); + if (!tileable(c)) { + kDebug(1212) << c->caption() << "is not tileable"; + t->floatTile(); + } + + if (!m_tilingLayouts.value(c->desktop())) { + m_tilingLayouts[c->desktop()] = TilingLayoutFactory::createLayout(TilingLayoutFactory::DefaultLayout, m_workspace); + m_tilingLayouts[c->desktop()]->setParent(this); + } + m_tilingLayouts[c->desktop()]->addTile(t); + m_tilingLayouts[c->desktop()]->commit(); + // if tiling is activated, connect to Client's signals and react with rearrangement when (un)minimizing + connect(c, SIGNAL(clientMinimized(KWin::Client*,bool)), this, SLOT(notifyTilingWindowMinimizeToggled(KWin::Client*))); + connect(c, SIGNAL(clientUnminimized(KWin::Client*,bool)), this, SLOT(notifyTilingWindowMinimizeToggled(KWin::Client*))); + connect(c, SIGNAL(s_unminimized()), this, SLOT(updateAllTiles())); +} + +void Tiling::removeTile(Client *c) +{ + if (!m_tilingLayouts.value(c->desktop())) { + return; + } + if (m_tilingLayouts[ c->desktop()]) + m_tilingLayouts[ c->desktop()]->removeTile(c); +} + +bool Tiling::tileable(Client* c) +{ + kDebug(1212) << c->caption(); + KWindowInfo info = KWindowSystem::windowInfo(c->window(), -1U, NET::WM2WindowClass); + kDebug(1212) << "WINDOW CLASS IS " << info.windowClassClass(); + if (info.windowClassClass() == "Plasma-desktop") { + return false; + } + // TODO: if application specific settings + // to ignore, put them here + + if (!c->isNormalWindow()) { + return false; + } + + // 0 means tile it, if we get 1 (floating), don't tile + if (c->rules()->checkTilingOption(0) == 1) { + return false; + } + + kDebug() << "Tiling" << c; + return true; +} + +void Tiling::belowCursor() +{ + // TODO +} + +Tile* Tiling::getNiceTile() const +{ + if (!isEnabled()) return NULL; + if (!m_tilingLayouts.value(m_workspace->activeClient()->desktop())) return NULL; + + return m_tilingLayouts[ m_workspace->activeClient()->desktop()]->findTile(m_workspace->activeClient()); + // TODO +} + +void Tiling::updateAllTiles() +{ + foreach (TilingLayout * t, m_tilingLayouts) { + if (!t) continue; + t->commit(); + } +} + +/* + * Resize the neighbouring clients to close any gaps + */ +void Tiling::notifyTilingWindowResize(Client *c, const QRect &moveResizeGeom, const QRect &orig) +{ + if (m_tilingLayouts.value(c->desktop()) == NULL) + return; + m_tilingLayouts[ c->desktop()]->clientResized(c, moveResizeGeom, orig); +} + +void Tiling::notifyTilingWindowMove(Client *c, const QRect &moveResizeGeom, const QRect &orig) +{ + if (m_tilingLayouts.value(c->desktop()) == NULL) { + return; + } + m_tilingLayouts[ c->desktop()]->clientMoved(c, moveResizeGeom, orig); + updateAllTiles(); +} + +void Tiling::notifyTilingWindowResizeDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled) +{ + if (canceled) + notifyTilingWindowResize(c, orig, moveResizeGeom); + else + notifyTilingWindowResize(c, moveResizeGeom, orig); +} + +void Tiling::notifyTilingWindowMoveDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled) +{ + if (canceled) + notifyTilingWindowMove(c, orig, moveResizeGeom); + else + notifyTilingWindowMove(c, moveResizeGeom, orig); +} + +void Tiling::notifyTilingWindowDesktopChanged(Client *c, int old_desktop) +{ + if (c->desktop() < 1 || c->desktop() > m_workspace->numberOfDesktops()) + return; + + if (m_tilingLayouts.value(old_desktop)) { + Tile *t = m_tilingLayouts[ old_desktop ]->findTile(c); + + // TODO: copied from createTile(), move this into separate method? + if (!m_tilingLayouts.value(c->desktop())) { + m_tilingLayouts[c->desktop()] = TilingLayoutFactory::createLayout(TilingLayoutFactory::DefaultLayout, m_workspace); + } + + if (t) + m_tilingLayouts[ c->desktop()]->addTile(t); + + m_tilingLayouts[ old_desktop ]->removeTile(c); + m_tilingLayouts[ old_desktop ]->commit(); + } +} + +/* + * Implements the 3 raising modes in Window Behaviour -> Advanced + */ +void Tiling::notifyTilingWindowActivated(KWin::Client *c) +{ + if (c == NULL) + return; + + if (options->tilingRaisePolicy == 1) // individual raise/lowers + return; + + if (m_tilingLayouts.value(c->desktop())) { + QList tiles = m_tilingLayouts[ c->desktop()]->tiles(); + + StackingUpdatesBlocker blocker(m_workspace); + + Tile *tile_to_raise = m_tilingLayouts[ c->desktop()]->findTile(c); + + if (!tile_to_raise) { + return; + } + + kDebug(1212) << "FOUND TILE"; + bool raise_floating = false; + if (options->tilingRaisePolicy == 2) // floating always on top + raise_floating = true; + else + raise_floating = tile_to_raise->floating(); + + foreach (Tile * t, tiles) { + if (t->floating() == raise_floating && t != tile_to_raise) + m_workspace->raiseClient(t->client()); + } + // raise the current tile last so that it ends up on top + // but only if it supposed to be raised, required to support tilingRaisePolicy + kDebug(1212) << "Raise floating? " << raise_floating << "to raise is floating?" << tile_to_raise->floating(); + if (tile_to_raise->floating() == raise_floating) + m_workspace->raiseClient(tile_to_raise->client()); + } +} + +void Tiling::notifyTilingWindowMinimizeToggled(KWin::Client* c) +{ + if (m_tilingLayouts.value(c->desktop())) { + m_tilingLayouts[ c->desktop()]->clientMinimizeToggled(c); + } +} + +void Tiling::notifyTilingWindowMaximized(Client *c, Options::WindowOperation op) +{ + if (m_tilingLayouts.value(c->desktop())) { + Tile *t = m_tilingLayouts[ c->desktop()]->findTile(c); + if (!t) { + createTile(c); + t = m_tilingLayouts[ c->desktop()]->findTile(c); + + // if still no tile, it couldn't be tiled + // so ignore it + if (!t) + return; + } + + // if window IS tiled and a maximize + // is attempted, make the window float. + // That is all we do since that can + // mess up the layout. + // In all other cases, don't do + // anything, let the user manage toggling + // using Meta+F + if (!t->floating() + && (op == Options::MaximizeOp + || op == Options::HMaximizeOp + || op == Options::VMaximizeOp)) { + m_tilingLayouts[ c->desktop()]->toggleFloatTile(c); + } + + } +} + +Tile* Tiling::findAdjacentTile(Tile *ref, int d) +{ + QRect reference = ref->geometry(); + QPoint origin = reference.center(); + + Tile *closest = NULL; + int minDist = -1; + + QList tiles = m_tilingLayouts[ ref->client()->desktop()]->tiles(); + + foreach (Tile * t, tiles) { + if (t->client() == ref->client() || t->ignoreGeometry()) + continue; + + bool consider = false; + + QRect other = t->geometry(); + QPoint otherCenter = other.center(); + + switch(d) { + case Tile::Top: + consider = otherCenter.y() < origin.y() + && other.bottom() < reference.top(); + break; + + case Tile::Right: + consider = otherCenter.x() > origin.x() + && other.left() > reference.right(); + break; + + case Tile::Bottom: + consider = otherCenter.y() > origin.y() + && other.top() > reference.bottom(); + break; + + case Tile::Left: + consider = otherCenter.x() < origin.x() + && other.right() < reference.left(); + break; + + default: + abort(); + } + + if (consider) { + int dist = (otherCenter - origin).manhattanLength(); + if (minDist > dist || minDist < 0) { + minDist = dist; + closest = t; + } + } + } + return closest; +} + +void Tiling::focusTile(int d) +{ + Tile *t = getNiceTile(); + if (t) { + Tile *adj = findAdjacentTile(t, d); + if (adj) + m_workspace->activateClient(adj->client()); + } +} + +void Tiling::moveTile(int d) +{ + Tile *t = getNiceTile(); + if (t) { + Tile* adj = findAdjacentTile(t, d); + + m_tilingLayouts[ t->client()->desktop()]->swapTiles(t, adj); + } +} + +void Tiling::slotFocusTileLeft() +{ + focusTile(Tile::Left); +} + +void Tiling::slotFocusTileRight() +{ + focusTile(Tile::Right); +} + +void Tiling::slotFocusTileTop() +{ + focusTile(Tile::Top); +} + +void Tiling::slotFocusTileBottom() +{ + focusTile(Tile::Bottom); +} + +void Tiling::slotMoveTileLeft() +{ + moveTile(Tile::Left); +} + +void Tiling::slotMoveTileRight() +{ + moveTile(Tile::Right); +} + +void Tiling::slotMoveTileTop() +{ + moveTile(Tile::Top); +} + +void Tiling::slotMoveTileBottom() +{ + moveTile(Tile::Bottom); +} + +void Tiling::slotToggleFloating() +{ + Client *c = m_workspace->activeClient(); + if (m_tilingLayouts.value(c->desktop())) { + m_tilingLayouts[ c->desktop()]->toggleFloatTile(c); + } +} + +void Tiling::slotNextTileLayout() +{ + if (m_tilingLayouts.value(m_workspace->currentDesktop())) { + + m_tilingLayouts.replace(m_workspace->currentDesktop(), TilingLayoutFactory::nextLayout(m_tilingLayouts[m_workspace->currentDesktop()])); + + m_tilingLayouts[m_workspace->currentDesktop()]->commit(); + } +} + +void Tiling::slotPreviousTileLayout() +{ + if (m_tilingLayouts.value(m_workspace->currentDesktop())) { + + m_tilingLayouts.replace(m_workspace->currentDesktop(), TilingLayoutFactory::previousLayout(m_tilingLayouts[m_workspace->currentDesktop()])); + + m_tilingLayouts[m_workspace->currentDesktop()]->commit(); + } +} + +KDecorationDefines::Position Tiling::supportedTilingResizeMode(Client *c, KDecorationDefines::Position currentMode) +{ + if (m_tilingLayouts.value(c->desktop())) { + return m_tilingLayouts[c->desktop()]->resizeMode(c, currentMode); + } + return currentMode; +} + +void Tiling::dumpTiles() const +{ + foreach (TilingLayout * t, m_tilingLayouts) { + if (!t) { + kDebug(1212) << "EMPTY DESKTOP"; + continue; + } + kDebug(1212) << "Desktop" << m_tilingLayouts.indexOf(t); + foreach (Tile * tile, t->tiles()) { + tile->dumpTile("--"); + } + } +} + +const QVector< TilingLayout* >& Tiling::tilingLayouts() const +{ + return m_tilingLayouts; +} + +void Tiling::slotResizeTilingLayouts() +{ + m_tilingLayouts.resize(m_workspace->numberOfDesktops() + 1); +} + +} diff --git a/tiling/tiling.h b/tiling/tiling.h new file mode 100644 index 0000000000..694bd9cde6 --- /dev/null +++ b/tiling/tiling.h @@ -0,0 +1,112 @@ +/******************************************************************** + KWin - the KDE window manager + This file is part of the KDE project. + +Copyright (C) 2009 Nikhil Marathe +Copyright (C) 2011 Arthur Arlt + +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 . +*********************************************************************/ + +#ifndef KWIN_TILING_H +#define KWIN_TILING_H + +#include + +#include "client.h" + +#include + +namespace KWin { + +class Tile; +class TilingLayout; + +class Tiling : public QObject { + Q_OBJECT +public: + Tiling(Workspace *w); + ~Tiling(); + bool isEnabled() const; + void setEnabled(bool tiling); + bool tileable(Client *c); + const QVector< TilingLayout* >& tilingLayouts() const; + void initShortcuts(KActionCollection* keys); + + // The notification functions are called from + // various points in existing code so that + // tiling can take any action if required. + // They are defined in tiling.cpp + void notifyTilingWindowResize(Client *c, const QRect &moveResizeGeom, const QRect &orig); + void notifyTilingWindowMove(Client *c, const QRect &moveResizeGeom, const QRect &orig); + void notifyTilingWindowResizeDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled); + void notifyTilingWindowMoveDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled); + void notifyTilingWindowDesktopChanged(Client *c, int old_desktop); + void notifyTilingWindowMaximized(Client *c, KDecorationDefines::WindowOperation op); + + KDecorationDefines::Position supportedTilingResizeMode(Client *c, KDecorationDefines::Position currentMode); + +public Q_SLOTS: + void createTile(KWin::Client *c); + void removeTile(KWin::Client *c); + // user actions, usually bound to shortcuts + // and also provided through the D-BUS interface. + void slotToggleTiling(); + void slotToggleFloating(); + void slotNextTileLayout(); + void slotPreviousTileLayout(); + + // Changes the focused client + void slotFocusTileLeft(); + void slotFocusTileRight(); + void slotFocusTileTop(); + void slotFocusTileBottom(); + // swaps active and adjacent client. + void slotMoveTileLeft(); + void slotMoveTileRight(); + void slotMoveTileTop(); + void slotMoveTileBottom(); + void belowCursor(); + + // NOTE: debug method + void dumpTiles() const; + + void notifyTilingWindowActivated(KWin::Client *c); +private: + // try to get a decent tile, either the one with + // focus or the one below the mouse. + Tile* getNiceTile() const; + // int, and not Tile::Direction because + // we are using a forward declaration for Tile + Tile* findAdjacentTile(Tile *ref, int d); + void focusTile(int d); + void moveTile(int d); + + Workspace* m_workspace; + bool m_enabled; + // Each tilingLayout is for one virtual desktop. + // The length is always one more than the number of + // virtual desktops so that we can quickly index them + // without having to remember to subtract one. + QVector m_tilingLayouts; +private Q_SLOTS: + void slotResizeTilingLayouts(); + void notifyTilingWindowMinimizeToggled(KWin::Client *c); + // updates geometry of tiles on all desktops, + // this rearranges the tiles. + void updateAllTiles(); +}; +} + +#endif // KWIN_TILING_H \ No newline at end of file diff --git a/tilinglayout.cpp b/tiling/tilinglayout.cpp similarity index 95% rename from tilinglayout.cpp rename to tiling/tilinglayout.cpp index 6e1152b15c..0e1d642ad5 100644 --- a/tilinglayout.cpp +++ b/tiling/tilinglayout.cpp @@ -18,20 +18,23 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . *********************************************************************/ -#include "tilinglayout.h" +#include "tiling/tilinglayout.h" #include #include "client.h" -#include "tile.h" +#include "tiling/tile.h" #include "workspace.h" +#include "tiling/tiling.h" namespace KWin { TilingLayout::TilingLayout(Workspace *w) - : m_workspace(w) + : QObject() + , m_workspace(w) { + connect(m_workspace, SIGNAL(configChanged()), this, SLOT(reconfigureTiling())); } TilingLayout::~TilingLayout() @@ -194,7 +197,7 @@ void TilingLayout::reconfigureTiling() foreach (Client * c, workspace()->stackingOrder()) { if (c->rules()->checkTilingOption(0) == 1) - workspace()->createTile(c); + workspace()->tiling()->createTile(c); } } diff --git a/tilinglayout.h b/tiling/tilinglayout.h similarity index 98% rename from tilinglayout.h rename to tiling/tilinglayout.h index 687d28c776..677db1aa00 100644 --- a/tilinglayout.h +++ b/tiling/tilinglayout.h @@ -33,8 +33,9 @@ class Workspace; class Client; class Tile; -class TilingLayout +class TilingLayout : public QObject { + Q_OBJECT public: TilingLayout(Workspace *w); virtual ~TilingLayout(); @@ -59,7 +60,6 @@ public: void removeTile(Client *c); void toggleFloatTile(Client *c); void swapTiles(Tile *a, Tile *b); - void reconfigureTiling(); /** * All tiling layouts do not allow the user to manually @@ -92,6 +92,9 @@ protected: virtual void postAddTile(Tile *t); virtual void preRemoveTile(Tile *t); +protected Q_SLOTS: + void reconfigureTiling(); + private: int findTilePos(Client *c) const; virtual void arrange(QRect wgeom) = 0; diff --git a/tilinglayoutfactory.cpp b/tilinglayoutfactory.cpp index 887b0b3ff0..78734e9f90 100644 --- a/tilinglayoutfactory.cpp +++ b/tilinglayoutfactory.cpp @@ -26,7 +26,7 @@ along with this program. If not, see . #include #include "notifications.h" -#include "tile.h" +#include "tiling/tile.h" #include "client.h" #include "tilinglayouts/spiral/spiral.h" diff --git a/tilinglayouts/columns/columns.cpp b/tilinglayouts/columns/columns.cpp index 0fd33d1a76..d0e1e1b5ec 100644 --- a/tilinglayouts/columns/columns.cpp +++ b/tilinglayouts/columns/columns.cpp @@ -21,7 +21,7 @@ along with this program. If not, see . #include "columns.h" #include "client.h" -#include "tile.h" +#include "tiling/tile.h" #include diff --git a/tilinglayouts/columns/columns.h b/tilinglayouts/columns/columns.h index bcd6f89d77..b8bb1f5469 100644 --- a/tilinglayouts/columns/columns.h +++ b/tilinglayouts/columns/columns.h @@ -23,7 +23,7 @@ along with this program. If not, see . #include -#include "tilinglayout.h" +#include "tiling/tilinglayout.h" namespace KWin { diff --git a/tilinglayouts/floating/floating.cpp b/tilinglayouts/floating/floating.cpp index a0c33e601e..e6623b649c 100644 --- a/tilinglayouts/floating/floating.cpp +++ b/tilinglayouts/floating/floating.cpp @@ -20,7 +20,7 @@ along with this program. If not, see . #include "floating.h" -#include "tile.h" +#include "tiling/tile.h" #include "client.h" namespace KWin diff --git a/tilinglayouts/floating/floating.h b/tilinglayouts/floating/floating.h index c3b40fa3b2..1c007cbfab 100644 --- a/tilinglayouts/floating/floating.h +++ b/tilinglayouts/floating/floating.h @@ -24,8 +24,8 @@ along with this program. If not, see . #include #include -#include "tilinglayout.h" -#include "tile.h" +#include "tiling/tilinglayout.h" +#include "tiling/tile.h" namespace KWin { diff --git a/tilinglayouts/spiral/spiral.cpp b/tilinglayouts/spiral/spiral.cpp index 979e001e52..b70be995e6 100644 --- a/tilinglayouts/spiral/spiral.cpp +++ b/tilinglayouts/spiral/spiral.cpp @@ -21,7 +21,7 @@ along with this program. If not, see . #include "spiral.h" #include "client.h" -#include "tile.h" +#include "tiling/tile.h" namespace KWin { diff --git a/tilinglayouts/spiral/spiral.h b/tilinglayouts/spiral/spiral.h index f5749f88ef..4621fb06fa 100644 --- a/tilinglayouts/spiral/spiral.h +++ b/tilinglayouts/spiral/spiral.h @@ -23,7 +23,7 @@ along with this program. If not, see . #include -#include "tilinglayout.h" +#include "tiling/tilinglayout.h" namespace KWin { diff --git a/useractions.cpp b/useractions.cpp index 387e4992b7..b6ee9a63e1 100644 --- a/useractions.cpp +++ b/useractions.cpp @@ -30,8 +30,11 @@ along with this program. If not, see . #include "client.h" #include "workspace.h" #include "effects.h" -#include "tile.h" -#include "tilinglayout.h" +#ifdef KWIN_BUILD_TILING +#include "tiling/tile.h" +#include "tiling/tilinglayout.h" +#include "tiling/tiling.h" +#endif #include "kactivityinfo.h" @@ -197,14 +200,16 @@ QMenu* Workspace::clientPopup() mTilingStateOpAction = popup->addAction(i18nc("When in tiling mode, toggle's the window's floating/tiled state", "&Float Window")); // then hide it mTilingStateOpAction->setVisible(false); +#ifdef KWIN_BUILD_TILING // actions for window tiling - if (tilingEnabled()) { + if (m_tiling->isEnabled()) { kaction = qobject_cast(keys->action("Toggle Floating")); mTilingStateOpAction->setCheckable(true); mTilingStateOpAction->setData(Options::ToggleClientTiledStateOp); if (kaction != 0) mTilingStateOpAction->setShortcut(kaction->globalShortcut().primary()); } +#endif popup->addSeparator(); @@ -289,16 +294,17 @@ void Workspace::clientPopupAboutToShow() mMinimizeOpAction->setEnabled(active_popup_client->isMinimizable()); mCloseOpAction->setEnabled(active_popup_client->isCloseable()); - if (tilingEnabled()) { +#ifdef KWIN_BUILD_TILING + if (m_tiling->isEnabled()) { int desktop = active_popup_client->desktop(); - if (tilingLayouts.value(desktop)) { - Tile *t = tilingLayouts[desktop]->findTile(active_popup_client); + if (m_tiling->tilingLayouts().value(desktop)) { + Tile *t = m_tiling->tilingLayouts()[desktop]->findTile(active_popup_client); if (t) mTilingStateOpAction->setChecked(t->floating()); } } - mTilingStateOpAction->setVisible(tilingEnabled()); - + mTilingStateOpAction->setVisible(m_tiling->isEnabled()); +#endif delete switch_to_tab_popup; switch_to_tab_popup = 0; delete add_tabs_popup; @@ -563,6 +569,11 @@ void Workspace::initShortcuts() if (tab_box) { tab_box->initShortcuts(actionCollection); } +#endif +#ifdef KWIN_BUILD_TILING + if (m_tiling) { + m_tiling->initShortcuts(actionCollection); + } #endif discardPopup(); // so that it's recreated next time } @@ -659,16 +670,16 @@ void Workspace::performWindowOperation(Client* c, Options::WindowOperation op) { if (!c) return; - +#ifdef KWIN_BUILD_TILING // Allows us to float a window when it is maximized, if it is tiled. - if (tilingEnabled() + if (m_tiling->isEnabled() && (op == Options::MaximizeOp || op == Options::HMaximizeOp || op == Options::VMaximizeOp || op == Options::RestoreOp)) { - notifyTilingWindowMaximized(c, op); + m_tiling->notifyTilingWindowMaximized(c, op); } - +#endif if (op == Options::MoveOp || op == Options::UnrestrictedMoveOp) QCursor::setPos(c->geometry().center()); if (op == Options::ResizeOp || op == Options::UnrestrictedResizeOp) @@ -779,10 +790,12 @@ void Workspace::performWindowOperation(Client* c, Options::WindowOperation op) case Options::CloseClientGroupOp: c->clientGroup()->closeAll(); case Options::ToggleClientTiledStateOp: { +#ifdef KWIN_BUILD_TILING int desktop = c->desktop(); - if (tilingLayouts.value(desktop)) { - tilingLayouts[desktop]->toggleFloatTile(c); + if (m_tiling->tilingLayouts().value(desktop)) { + m_tiling->tilingLayouts()[desktop]->toggleFloatTile(c); } +#endif } } } diff --git a/workspace.cpp b/workspace.cpp index b9556681b2..74a854e5ef 100644 --- a/workspace.cpp +++ b/workspace.cpp @@ -44,7 +44,6 @@ along with this program. If not, see . #include #include "client.h" -#include "tile.h" #ifdef KWIN_BUILD_TABBOX #include "tabbox.h" #endif @@ -62,8 +61,11 @@ along with this program. If not, see . #include "deleted.h" #include "effects.h" #include "overlaywindow.h" -#include "tilinglayout.h" - +#ifdef KWIN_BUILD_TILING +#include "tiling/tile.h" +#include "tiling/tilinglayout.h" +#include "tiling/tiling.h" +#endif #ifdef KWIN_BUILD_SCRIPTING #include "scripting/scripting.h" #endif @@ -107,7 +109,6 @@ Workspace::Workspace(bool restore) , desktopGridSize_(1, 2) // Default to two rows , desktopGrid_(new int[2]) , currentDesktop_(0) - , tilingEnabled_(false) // Unsorted , active_popup(NULL) , active_popup_client(NULL) @@ -235,11 +236,16 @@ Workspace::Workspace(bool restore) ); client_keys = new KActionCollection(this); - initShortcuts(); + #ifdef KWIN_BUILD_DESKTOPCHANGEOSD desktop_change_osd = new DesktopChangeOSD(this); #endif m_outline = new Outline(); +#ifdef KWIN_BUILD_TILING + m_tiling = new Tiling(this); +#endif + + initShortcuts(); init(); @@ -487,8 +493,10 @@ void Workspace::init() if (new_active_client != NULL) activateClient(new_active_client); +#ifdef KWIN_BUILD_TILING // Enable/disable tiling - setTilingEnabled(options->tilingOn); + m_tiling->setEnabled(options->tilingOn); +#endif // SELI TODO: This won't work with unreasonable focus policies, // and maybe in rare cases also if the selected client doesn't @@ -502,6 +510,9 @@ Workspace::~Workspace() { finishCompositing(); blockStackingUpdates(true); +#ifdef KWIN_BUILD_TILING + delete m_tiling; +#endif // TODO: grabXServer(); @@ -562,9 +573,8 @@ Client* Workspace::createClient(Window w, bool is_mapped) } addClient(c, Allowed); - tilingLayouts.resize(numberOfDesktops() + 1); + m_tiling->createTile(c); - createTile(c); return c; } @@ -668,9 +678,6 @@ void Workspace::removeClient(Client* c, allowed_t) #endif Q_ASSERT(clients.contains(c) || desktops.contains(c)); - if (tilingEnabled() && tilingLayouts.value(c->desktop())) { - removeTile(c); - } // TODO: if marked client is removed, notify the marked list clients.removeAll(c); desktops.removeAll(c); @@ -1027,13 +1034,11 @@ void Workspace::slotReconfigure() } } - setTilingEnabled(options->tilingOn); - foreach (TilingLayout * layout, tilingLayouts) { - if (layout) - layout->reconfigureTiling(); - } +#ifdef KWIN_BUILD_TILING + m_tiling->setEnabled(options->tilingOn); // just so that we reset windows in the right manner, 'activate' the current active window - notifyTilingWindowActivated(activeClient()); + m_tiling->notifyTilingWindowActivated(activeClient()); +#endif if (hasDecorationPlugin()) { rootInfo->setSupported(NET::WM2FrameOverlap, mgr->factory()->supports(AbilityExtendIntoClientArea)); } else { @@ -1296,9 +1301,13 @@ bool Workspace::setCurrentDesktop(int new_desktop) if (movingClient && !movingClient->isOnDesktop(new_desktop)) { int old_desktop = movingClient->desktop(); movingClient->setDesktop(new_desktop); - if (tilingEnabled()) { - notifyTilingWindowDesktopChanged(movingClient, old_desktop); +#ifdef KWIN_BUILD_TILING + if (m_tiling->isEnabled()) { + m_tiling->notifyTilingWindowDesktopChanged(movingClient, old_desktop); } +#else + Q_UNUSED(old_desktop) +#endif } for (int i = stacking_order.size() - 1; i >= 0 ; --i) @@ -1577,8 +1586,6 @@ void Workspace::setNumberOfDesktops(int n) for (int i = 0; i < int(desktop_focus_chain.size()); i++) desktop_focus_chain[i] = i + 1; - tilingLayouts.resize(numberOfDesktops() + 1); - saveDesktopSettings(); emit numberDesktopsChanged(old_number_of_desktops); } @@ -1611,7 +1618,9 @@ void Workspace::sendClientToDesktop(Client* c, int desk, bool dont_activate) } else raiseClient(c); - notifyTilingWindowDesktopChanged(c, old_desktop); +#ifdef KWIN_BUILD_TILING + m_tiling->notifyTilingWindowDesktopChanged(c, old_desktop); +#endif ClientList transients_stacking_order = ensureStackingOrder(c->transients()); for (ClientList::ConstIterator it = transients_stacking_order.constBegin(); @@ -2151,6 +2160,57 @@ TabBox::TabBox* Workspace::tabBox() const } #endif +#ifdef KWIN_BUILD_TILING +Tiling* Workspace::tiling() +{ + return m_tiling; +} +#endif + +/* + * Called from D-BUS + */ +void Workspace::toggleTiling() +{ +#ifdef KWIN_BUILD_TILING + if (m_tiling) { + m_tiling->slotToggleTiling(); + } +#endif +} + +/* + * Called from D-BUS + */ +void Workspace::nextTileLayout() +{ +#ifdef KWIN_BUILD_TILING + if (m_tiling) { + m_tiling->slotNextTileLayout(); + } +#endif +} + +/* + * Called from D-BUS + */ +void Workspace::previousTileLayout() +{ +#ifdef KWIN_BUILD_TILING + if (m_tiling) { + m_tiling->slotPreviousTileLayout(); + } +#endif +} + +void Workspace::dumpTiles() const { +#ifdef KWIN_BUILD_TILING + if (m_tiling) { + m_tiling->dumpTiles(); + } +#endif +} + } // namespace #include "workspace.moc" diff --git a/workspace.h b/workspace.h index 79c1e2d691..492d1ca33b 100644 --- a/workspace.h +++ b/workspace.h @@ -73,8 +73,11 @@ class TabBox; #endif class Client; +#ifdef KWIN_BUILD_TILING class Tile; +class Tiling; class TilingLayout; +#endif class ClientGroup; #ifdef KWIN_BUILD_DESKTOPCHANGEOSD class DesktopChangeOSD; @@ -197,31 +200,9 @@ public: return unmanaged; } - //------------------------------------------------- - // Tiling -public: - bool tilingEnabled() const; - void setTilingEnabled(bool tiling); - bool tileable(Client *c); - void createTile(Client *c); - // updates geometry of tiles on all desktops, - // this rearranges the tiles. - void updateAllTiles(); - - // The notification functions are called from - // various points in existing code so that - // tiling can take any action if required. - // They are defined in tiling.cpp - void notifyTilingWindowResize(Client *c, const QRect &moveResizeGeom, const QRect &orig); - void notifyTilingWindowMove(Client *c, const QRect &moveResizeGeom, const QRect &orig); - void notifyTilingWindowResizeDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled); - void notifyTilingWindowMoveDone(Client *c, const QRect &moveResizeGeom, const QRect &orig, bool canceled); - void notifyTilingWindowDesktopChanged(Client *c, int old_desktop); - void notifyTilingWindowActivated(Client *c); - void notifyTilingWindowMinimizeToggled(Client *c); - void notifyTilingWindowMaximized(Client *c, WindowOperation op); - - Position supportedTilingResizeMode(Client *c, Position currentMode); +#ifdef KWIN_BUILD_TILING + Tiling* tiling(); +#endif Outline* outline(); #ifdef KWIN_BUILD_SCREENEDGES @@ -329,13 +310,9 @@ private: KActivityController activityController_; - bool tilingEnabled_; - // Each tilingLayout is for one virtual desktop. - // The length is always one more than the number of - // virtual desktops so that we can quickly index them - // without having to remember to subtract one. - QVector tilingLayouts; - +#ifdef KWIN_BUILD_TILING + Tiling* m_tiling; +#endif Outline* m_outline; #ifdef KWIN_BUILD_SCREENEDGES ScreenEdge m_screenEdge; @@ -640,25 +617,6 @@ public slots: void suspendCompositing(); void suspendCompositing(bool suspend); - // user actions, usually bound to shortcuts - // and also provided through the D-BUS interface. - void slotToggleTiling(); - void slotToggleFloating(); - void slotNextTileLayout(); - void slotPreviousTileLayout(); - - // Changes the focused client - void slotFocusTileLeft(); - void slotFocusTileRight(); - void slotFocusTileTop(); - void slotFocusTileBottom(); - // swaps active and adjacent client. - void slotMoveTileLeft(); - void slotMoveTileRight(); - void slotMoveTileTop(); - void slotMoveTileBottom(); - void belowCursor(); - // NOTE: debug method void dumpTiles() const; @@ -805,16 +763,6 @@ private: static NET::WindowType txtToWindowType(const char* txt); static bool sessionInfoWindowTypeMatch(Client* c, SessionInfo* info); - // try to get a decent tile, either the one with - // focus or the one below the mouse. - Tile* getNiceTile() const; - void removeTile(Client *c); - // int, and not Tile::Direction because - // we are using a forward declaration for Tile - Tile* findAdjacentTile(Tile *ref, int d); - void focusTile(int d); - void moveTile(int d); - Client* active_client; Client* last_active_client; Client* most_recently_raised; // Used ONLY by raiseOrLowerClient() @@ -1263,30 +1211,6 @@ inline void Workspace::removeClientGroup(ClientGroup* group) clientGroups.removeAll(group); } -/* - * Called from D-BUS - */ -inline void Workspace::toggleTiling() -{ - slotToggleTiling(); -} - -/* - * Called from D-BUS - */ -inline void Workspace::nextTileLayout() -{ - slotNextTileLayout(); -} - -/* - * Called from D-BUS - */ -inline void Workspace::previousTileLayout() -{ - slotPreviousTileLayout(); -} - } // namespace #endif