diff options
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | dummy | 0 | ||||
-rw-r--r-- | src/tiles.cpp | 936 | ||||
-rw-r--r-- | src/tiles.h | 245 | ||||
-rw-r--r-- | tiles.xml.in | 7 |
5 files changed, 1195 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a5e9538 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +find_package (Compiz REQUIRED) + +include (CompizPlugin) + +set (CMAKE_CXX_FLAGS -std=c++0x) + +compiz_plugin (tiles PLUGINDEPS composite opengl) diff --git a/src/tiles.cpp b/src/tiles.cpp new file mode 100644 index 0000000..5873ae1 --- /dev/null +++ b/src/tiles.cpp @@ -0,0 +1,936 @@ +/* + * Compiz Tiles Plugin + * + * tiles.cpp + * + * Copyright (c) 2011 Sam Spilsbury <smspillaz@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 3 + * 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. + */ + +#include "tiles.h" + +COMPIZ_PLUGIN_20090315 (tiles, TilesPluginVTable); + +Tile::Tile (TileLayerPtr parent) : + priv (new PrivateTile) +{ + priv->mParent = parent; + priv->mProgress = 0.0f; + priv->mWindow = NULL; +} + +Tile::~Tile() +{ + if (priv->mWindow) + { + XWindowChanges xwc; + xwc.x = priv->mSaveGeometry.x (); + xwc.y = priv->mSaveGeometry.y (); + xwc.width = priv->mSaveGeometry.width (); + xwc.height = priv->mSaveGeometry.height (); + + priv->mWindow->configureXWindow (priv->mSaveMask, &xwc); + } + + delete priv; +} + +CompRect +Tile::rect () +{ + return priv->mRect; +} + +CompWindow * +Tile::window () +{ + return priv->mWindow; +} + +bool +Tile::allocateWindow (CompWindow *w) +{ + if (priv->mWindow) + return false; + + priv->mWindow = w; + priv->mSaveGeometry = priv->mWindow->serverGeometry (); + priv->mSaveMask = CWX | CWY | CWWidth | CWHeight; + + return true; +} + +const unsigned int anim_time = 300; + +bool +Tile::animate (unsigned int ms) +{ + priv->mProgress += ms / static_cast <float> (anim_time); + + if (priv->mProgress >= anim_time) + { + priv->mProgress = anim_time; + return false; + } + + return true; +} + +void +Tile::lockTargetSize() +{ + CompRect resizeTarget = priv->mRect; + + resized (resizeTarget); + + XWindowChanges xwc; + unsigned int valueMask; + + valueMask = CWX | CWY | CWWidth | CWHeight; + xwc.x = resizeTarget.x (); + xwc.y = resizeTarget.y (); + xwc.width = resizeTarget.width (); + xwc.height = resizeTarget.height (); + + priv->mWindow->configureXWindow (valueMask, &xwc); +} + +void +Tile::resized (CompRect &r) +{ + r.setX (r.x () + priv->mWindow->border ().left); + r.setWidth (r.width () - priv->mWindow->border ().right + - priv->mWindow->border ().left); + r.setY (r.y () + priv->mWindow->border ().top); + r.setHeight (r.height () - priv->mWindow->border ().bottom + - priv->mWindow->border ().top); +} + +GLVector +Tile::scale () +{ + GLVector v; + + v[GLVector::x] = std::min (1.0f, priv->mWindow->serverBorderRect ().width () / static_cast <float> (priv->mRect.width ())); + v[GLVector::y] = std::min (1.0f, priv->mWindow->serverBorderRect ().height () / static_cast <float> (priv->mRect.height ())); + v[GLVector::z] = 1.0f; + v[GLVector::w] = 1.0f; + + return v; +} + +bool +Tile::setTargetSize (CompRect &r) +{ + priv->mRect = r; + return true; +} + +const std::vector<Tile::Ptr> & +TileLayer::tiles () +{ + return priv->mTiles; +} + +void +TileLayer::handleWindowResize (CompWindow *output) +{ + CompRegion available = priv->mOutput->workArea (); + + /* Resize all the other tiles accordingly by + * calculating the gaps in the current tile + * layer and filling them + * FIXME: this could probably be a lot more + * optimized rather than crunching regions */ + + for (Tile::Ptr t : priv->mTiles) + { + available -= t->rect (); + } + + /* Search tiles for available space, resize where possible */ + for (const CompRect &r : available.rects ()) + { + } +} + +const unsigned int drop_zone_area = 20; + +void +Tile::grab () +{ +} + +const unsigned int max_drag = 20; + +bool +Tile::drag (CompPoint &p) +{ + priv->mDragBuffer += p; + + float factor = sqrt (pow (abs (priv->mDragBuffer.x ()), 2) + + pow (abs (priv->mDragBuffer.y ()), 2)); + + if (factor >= max_drag) + return true; + + return false; +} + +void +Tile::ungrab () +{ + priv->mDragBuffer = CompPoint (); +} + +void +TileLayer::handleWindowGrabbed (CompWindow *w) +{ + priv->mPushedSpaces.clear(); + + /* Recalculate drop zones */ + if (tiles ().empty ()) + { + priv->mDropZones = CompRegion (*priv->mOutput) - + CompRegion (priv->mOutput->x () + drop_zone_area, priv->mOutput->y () + drop_zone_area, + priv->mOutput->width () - drop_zone_area * 2, priv->mOutput->height () - drop_zone_area * 2); + } + else + { + priv->mDropZones = CompRegion (*priv->mOutput); + for (const Tile::Ptr &tp : tiles ()) + { + priv->mDropZones -= CompRegion (tp->rect ().x () + drop_zone_area, tp->rect ().y () + drop_zone_area, + tp->rect ().width () - drop_zone_area * 2, tp->rect ().height () - drop_zone_area * 2); + } + } + + priv->mLastPointer = CompPoint (pointerX, pointerY); +} + +void +TileLayer::handleWindowUngrabbed (CompWindow *w) +{ + CompPoint p (pointerX, pointerY); + RectMap::Map::iterator it = priv->mPushedSpaces.begin (); + std::vector <Tile::Ptr>::iterator tpit = priv->mTiles.begin (); + + for (; tpit != priv->mTiles.end (); tpit++) + { + if ((*tpit)->window () == w) + break; + } + + if (tpit == priv->mTiles.end ()) + { + for (; it != priv->mPushedSpaces.end (); it++) + { + if (it->first.contains (p)) + { + addWindow (w, it->second); + break; + } + } + } + else + (*tpit)->ungrab (); +} + +void +PrivateTileLayer::pushSpace (CompRect r) +{ + CompRect available = mOutput->workArea (); + unsigned int nTiles = 0; + + if (mPushedSpaces.find (r) != mPushedSpaces.end ()) + return; + + /* Calculate what this space expands to : + * If this stip is longer than it is wider, + * expand it horizontally, otherwise + * vertically */ + + if (r.height () > r.width ()) + { + available.setHeight (r.height ()); + available.setY (r.y ()); + + /* The way the region calculation works out + * means that there might be some extra space + * so work out if there are any other tiles partially + * overlapping workArea.height () * r.width () + * and then add the empty spaces */ + CompRegion bar = CompRegion (r.x (), mOutput->workArea ().y (), r.width (), mOutput->workArea ().height ()); + CompRegion origBar = bar; + + for (const Tile::Ptr &tp : mTiles) + { + bar -= tp->rect (); + if (tp->rect ().y () == origBar.boundingRect ().y ()) + { + nTiles++; + } + } + + if (bar.isEmpty () || + (bar - CompRegion (r.x (), mOutput->workArea ().y (), + r.width (), mOutput->workArea ().height ())).isEmpty ()) + { + available.setY (origBar.boundingRect ().y ()); + available.setHeight (origBar.boundingRect ().height ()); + } + + /* Divide by number of tiles + 1, this will be + * the space we need to occupy */ + + unsigned int width = available.width () / (nTiles + 1); + + /* Prefer going left to right unless we'd go offscreen that way */ + if (r.x () + width > mOutput->width ()) + available.setX (r.x2 () - width); + else + available.setX (r.x ()); + + available.setWidth (width); + } + else + { + available.setWidth (r.width ()); + available.setX (r.x ()); + + /* The way the region calculation works out + * means that there might be some extra space + * so work out if there are any other tiles partially + * overlapping workArea.height () * r.width () + * and then add the empty spaces */ + CompRegion bar = CompRegion (r.x (), mOutput->workArea ().y (), r.width (), mOutput->workArea ().height ()); + CompRegion origBar = bar; + + for (const Tile::Ptr &tp : mTiles) + { + bar -= tp->rect (); + if (tp->rect ().x () == origBar.boundingRect ().x ()) + nTiles++; + } + + if (bar.isEmpty () || + (bar - CompRegion (mOutput->workArea ().x (), r.y (), + mOutput->workArea ().width (), r.height ())).isEmpty ()) + { + available.setX (origBar.boundingRect ().x ()); + available.setWidth (origBar.boundingRect ().width ()); + } + + /* Divide by number of tiles + 1, this will be + * the space we need to occupy */ + + unsigned int height = available.height () / (nTiles + 1); + + /* Prefer going top to bottom unless we'd go offscreen that way */ + if (r.y () + height > mOutput->height ()) + available.setY (r.y2 () - height); + else + available.setY (r.y ()); + + available.setHeight (height); + } + + mPushedSpaces[r] = available; +} + +void +PrivateTileLayer::popSpaces () +{ + mPushedSpaces.clear (); +} + +void +TileLayer::handleWindowGrabMovement (CompWindow *w, CompPoint &p) +{ + bool spaceFound = false; + std::vector <Tile::Ptr>::iterator tpit = priv->mTiles.begin (); + + for (; tpit != priv->mTiles.end (); tpit++) + { + if ((*tpit)->window () == w) + break; + } + + if (tpit == priv->mTiles.end ()) + { + for (CompRect r : priv->mDropZones.rects ()) + { + if (CompRegion (r).contains (p)) + { + /* expand r to next tile space */ + priv->pushSpace (r); + spaceFound = true; + } + } + + if (!spaceFound) + priv->popSpaces (); + } + else + { + CompPoint dp = priv->mLastPointer - p; + + if (!(*tpit)->drag (dp)) + { + int dx = dp.x (); + int dy = dp.y (); + + w->move (dx, dy, true); + w->syncPosition (); + } + else + removeWindow (w); + } + + priv->mLastPointer = p; +} + +bool +TileLayer::tilesToRegion (std::vector <Tile::Ptr> tiles, + CompRegion tilesRegion, + CompRegion nextRegion) +{ + for (Tile::Ptr tp : tiles) + { + float xScale = nextRegion.boundingRect ().width () / static_cast <float> (tilesRegion.boundingRect ().width ()); + float yScale = nextRegion.boundingRect ().height () / static_cast <float> (tilesRegion.boundingRect ().height ()); + + CompPoint pos = tp->rect ().pos () - tilesRegion.boundingRect ().pos (); + CompRect nextPosition; + + /* Scale the new positions */ + pos.setX (pos.x () * xScale); + pos.setY (pos.y () * yScale); + + pos += nextRegion.boundingRect ().pos (); + + /* Now scale the sizes */ + nextPosition.setWidth (tp->rect ().width () * xScale); + nextPosition.setHeight (tp->rect ().height () * yScale); + + nextPosition.setPos (pos); + + if (!tp->setTargetSize (nextPosition)) + return false; + } + + return true; +} + +bool +TileLayer::addWindow (CompWindow *w, CompRect &r) +{ + Tile::Ptr t = Tile::Ptr (new Tile (shared_from_this ())); + std::vector <Tile::Ptr> intersectingTiles; + CompRegion intersectingTilesRegion; + CompRegion insertRegion (r); + + /* Expand like this: + * ------------- + * | | + * | | + * | | + * | | + * | | + * ------------------------------------ + * | | | | + * | | | | + * | | | | + * | | | | + * |----------|-----------------------| + * | | + * | | + * | | + * | | + * | | + * ------------- + */ + + insertRegion += CompRegion (r.x (), r.y (), priv->mOutput->workArea ().width () - r.x2 (), r.height ()); + insertRegion += CompRegion (r.x (), r.y (), r.width (), priv->mOutput->workArea ().width () - r.y2 ()); + insertRegion += CompRegion (priv->mOutput->workArea ().x (), r.y (), r.x () - priv->mOutput->workArea().x (), r.height ()); + insertRegion += CompRegion (r.x (), priv->mOutput->workArea ().y (), r.width (), r.y () - priv->mOutput->workArea ().y ()); + + + if (!t->allocateWindow (w)) + return false; + + /* Allocate a new space for this window + * and change the target size of other windows */ + if (!t->setTargetSize (r)) + return false; + + /* Now reallocate the other tiles that intersect this one */ + for (Tile::Ptr tp : priv->mTiles) + { + if (CompRegion (tp->rect ()).intersects (insertRegion)) + { + intersectingTiles.push_back (tp); + intersectingTilesRegion += tp->rect (); + } + } + + CompRegion allowedRegion = intersectingTilesRegion - r; + + if (!tilesToRegion (intersectingTiles, intersectingTilesRegion, allowedRegion)) + return false; + + priv->mTiles.push_back (t); + + for (Tile::Ptr tp : priv->mTiles) + tp->lockTargetSize (); + + priv->popSpaces (); +} + +void +TileLayer::removeWindow (CompWindow *w) +{ + std::vector <Tile::Ptr>::iterator tpit = priv->mTiles.begin (); + std::vector <Tile::Ptr> resizeTiles; + CompRegion tilesRegion; + + for (; tpit != priv->mTiles.end (); tpit++) + { + if ((*tpit)->window () == w) + { + priv->mTiles.erase (tpit); + break; + } + } + + /* Now calculate the empty space and find any tiles contained + * in that space and expand them evenly to fill the empty space + * created by the newly removed tile */ + + CompRegion reg = priv->mOutput->workArea (); + + for (Tile::Ptr tp : priv->mTiles) + reg -= tp->rect (); + + CompRegion insertRegion = reg; + CompRect r = reg.boundingRect (); + + /* Expand the rect towards screen edges (as illustrated above) */ + insertRegion += CompRegion (r.x (), r.y (), priv->mOutput->workArea ().width () - r.x2 (), r.height ()); + insertRegion += CompRegion (r.x (), r.y (), r.width (), priv->mOutput->workArea ().width () - r.y2 ()); + insertRegion += CompRegion (priv->mOutput->workArea ().x (), r.y (), r.x () - priv->mOutput->workArea().x (), r.height ()); + insertRegion += CompRegion (r.x (), priv->mOutput->workArea ().y (), r.width (), r.y () - priv->mOutput->workArea ().y ()); + + /* Now find any windows which are directly contained by this + * cross-shaped region */ + for (Tile::Ptr tp : priv->mTiles) + { + if ((CompRegion (tp->rect ()) - insertRegion).isEmpty ()) + { + resizeTiles.push_back (tp); + tilesRegion += tp->rect (); + } + } + + reg += tilesRegion; + + if (tilesToRegion (resizeTiles, tilesRegion, reg)); + for (Tile::Ptr tp : resizeTiles) + tp->lockTargetSize (); +} + +bool +TileLayer::animate (unsigned int ms) +{ + bool done = false; + + for (const Tile::Ptr &p : tiles ()) + done |= p->animate (ms); + + if (done) + { + /* Check the layer animation too */ + // ?? + } + + return done; +} + +void +TileLayer::paintOutline(const GLMatrix &m) +{ + return; +} + +void +Tile::damage () +{ + if (priv->mWindow) + { + std::vector <GLVector> vecs = { GLVector (priv->mWindow->serverBorderRect ().x (), priv->mWindow->serverBorderRect ().y (), 1.0f, 1.0f), // top left + GLVector (priv->mWindow->serverBorderRect ().x2 (), priv->mWindow->serverBorderRect ().y2 (), 1.0f, 1.0f) }; // bottom right + + GLMatrix sMatrix; + + sMatrix.scale (scale ()); + + for (GLVector &v : vecs) + { + v = sMatrix * v; + } + + CompRegion reg (vecs[0][GLVector::x], vecs[0][GLVector::y], + vecs[1][GLVector::x] - vecs[0][GLVector::x], + vecs[1][GLVector::y] - vecs[0][GLVector::y]); + + CompositeScreen::get (screen)->damageRegion (reg); + } +} + +void +TileLayer::damage () +{ + for (const Tile::Ptr &p : tiles ()) + p->damage (); +} + +TileLayer::TileLayer (CompOutput *output) : + priv (new PrivateTileLayer) +{ + priv->mOutput = output; +} + +TileLayer::~TileLayer () +{ + delete priv; +} + +void +TilesWindow::grabNotify (int x, int y, unsigned int state, unsigned int mask) +{ + if (mask & (CompWindowGrabMoveMask | CompWindowGrabButtonMask)) + { + if (!priv->mTile) + priv->window->moveNotifySetEnabled (this, true); + TilesScreen::get (screen)->addGrabbedWindow (this); + } + + priv->window->grabNotify (x, y, state, mask); +} + +void +TilesWindow::ungrabNotify () +{ + TilesScreen::get (screen)->removeGrabbedWindow (this); + + if (!priv->mTile) + priv->window->moveNotifySetEnabled (this, false); + + priv->window->ungrabNotify (); +} + +void +TilesWindow::moveNotify (int dx, int dy, bool immediate) +{ + TilesScreen::get (screen)->dragGrabbedWindow (this, CompPoint (pointerX, pointerY)); + + priv->window->moveNotify (dx, dy, immediate); +} + +void +TilesWindow::resizeNotify (int dx, int dy, int dwidth, int dheight) +{ + if (priv->mTile) + { + CompRect g (static_cast <CompRect &> (priv->window->geometry ())); + priv->mTile->resized (g); + } + + priv->window->resizeNotify (dx, dy, dwidth, dheight); +} + +void +TilesWindow::validateResizeRequest (unsigned int &mask, + XWindowChanges *xwc, + unsigned int source) +{ + priv->window->validateResizeRequest (mask, xwc, source); + + /* force xwc to be the current geometry */ + xwc->x = priv->window->geometry().x (); + xwc->y = priv->window->geometry().y (); + xwc->width = priv->window->geometry().width (); + xwc->height = priv->window->geometry().height (); +} + +bool +TilesWindow::glPaint (const GLWindowPaintAttrib &attrib, const GLMatrix &matrix, + const CompRegion ®ion, unsigned int mask) +{ + if (priv->mTile) + { + GLVector scale = { 1.0f, 1.0f, 1.0f, 1.0f }; + GLVector translation = { 0.0f, 0.0f, 0.0f, 0.0f }; + GLMatrix wTransform (matrix); + const CompRect &rect = priv->mTile->rect (); + + /* First translate to the target rectangle such + * that the center of the window geometry is the + * center of the target rectangle */ + + translation[GLVector::x] = rect.centerX () - priv->window->geometry ().centerX (); + translation[GLVector::y] = rect.centerY () - priv->window->geometry ().centerY (); + + scale[GLVector::x] = rect.width () / static_cast <float> (priv->window->geometry ().width ()); + scale[GLVector::y] = rect.height () / static_cast <float> (priv->window->geometry ().height ()); + + wTransform.translate (translation); + wTransform.scale (scale); + + translation[GLVector::x] = -(rect.centerX () - priv->window->geometry ().centerX ()); + translation[GLVector::y] = -(rect.centerY () - priv->window->geometry ().centerY ()); + + wTransform.translate (translation); + + mask |= PAINT_WINDOW_TRANSFORMED_MASK; + } + + priv->gWindow->glPaint (attrib, matrix, region, mask); +} + +bool +TilesWindow::damageRect (bool initial, const CompRect &rect) +{ + bool ret = false; + + if (priv->mTile) + { + ret = true; + + std::vector <GLVector> vec = { GLVector (rect.x1 (), rect.y1 (), 0.0, 1.0), + GLVector (rect.x2 (), rect.y1 (), 0.0, 1.0), + GLVector (rect.x1 (), rect.y2 (), 0.0, 1.0), + GLVector (rect.x2 (), rect.y2 (), 0.0, 1.0) + }; + + /* Determine scaling matrix */ + GLMatrix matrix; + GLVector scale; + GLVector translation; + + translation[GLVector::x] = rect.centerX () - priv->window->geometry ().centerX (); + translation[GLVector::y] = rect.centerY () - priv->window->geometry ().centerY (); + + scale[GLVector::x] = rect.width () / static_cast <float> (priv->window->geometry ().width ()); + scale[GLVector::y] = rect.height () / static_cast <float> (priv->window->geometry ().height ()); + + matrix.translate (translation); + matrix.scale (scale); + + translation[GLVector::x] = -(rect.centerX () - priv->window->geometry ().centerX ()); + translation[GLVector::y] = -(rect.centerY () - priv->window->geometry ().centerY ()); + + matrix.translate (translation); + + /* Now multiply damage co-ords and damage region */ + for (GLVector &v : vec) + v = matrix * v; + + CompRect r = CompRect (vec[0][GLVector::x], vec[0][GLVector::y], + vec[1][GLVector::x] - vec[0][GLVector::x], + vec[2][GLVector::y] - vec[0][GLVector::y]); + CompRegion reg (r); + + CompositeScreen::get (screen)->damageRegion (reg); + } + + priv->cWindow->damageRect(initial, rect); + + return ret; +} + +bool +TilesWindow::animate(unsigned int ms) +{ + return priv->mTile->animate (ms); +} + +void +TilesWindow::damage () +{ + priv->cWindow->addDamage (true); +} + +void +TilesScreen::dragGrabbedWindow (TilesWindow *tw, CompPoint pointer) +{ + if (priv->mTileLayers.size ()) + priv->mTileLayers.front ()->handleWindowGrabMovement (tw->window (), pointer); +} + +void +TilesScreen::removeGrabbedWindow (TilesWindow *tw) +{ + auto it = std::find (priv->mDraggedWindows.begin (), priv->mDraggedWindows.end (), tw); + + if (it != priv->mDraggedWindows.end ()) + priv->mDraggedWindows.erase (it); + + if (!priv->mTileLayers.empty ()) + priv->mTileLayers.back ()->handleWindowUngrabbed (tw->window ()); + + /* No more dragged windows and the last tile layer is empty, + * delete it */ + + if (priv->mTileLayers.size () == 1) + if (priv->mTileLayers.front ()->tiles ().empty ()) + priv->mTileLayers.clear (); +} + +void +TilesScreen::addGrabbedWindow (TilesWindow *tw) +{ + TileLayer::Ptr tp; + + /* If there is no layers then we should create one */ + if (priv->mTileLayers.empty ()) + { + tp = TileLayer::Ptr (new TileLayer (&screen->outputDevs ()[tw->window ()->outputDevice ()])); + + priv->mTileLayers.push_back (tp); + } + else + tp = priv->mTileLayers.back (); + + if (std::find (priv->mDraggedWindows.begin (), priv->mDraggedWindows.end (), tw) + != priv->mDraggedWindows.end ()) + priv->mDraggedWindows.push_back (tw); + + tp->handleWindowGrabbed (tw->window ()); + + //tw->priv->window->moveNotifySetEnabled (tw, true); +} + +void +TilesScreen::preparePaint (int ms) +{ + bool continueAnimation = false; + + for (TileLayer::Ptr p : priv->mTileLayers) + continueAnimation = p->animate (ms); + + for (TilesWindow *tw : priv->mDraggedWindows) + continueAnimation = tw->animate (ms); + + priv->cScreen->preparePaint (ms); +} + +bool +TilesScreen::glPaintOutput (const GLScreenPaintAttrib &attrib, const GLMatrix &matrix, + const CompRegion ®ion, CompOutput *output, unsigned int mask) +{ + bool continueAnimation = priv->mDraggedWindows.size () ? true : false; + + /* continueAnimation means that there are scaled windows + * around so we need to allow painting with custom vertex + * layouts */ + for (TileLayer::Ptr p : priv->mTileLayers) + { + continueAnimation |= p->animate (0); + } + + for (TilesWindow *tw : priv->mDraggedWindows) + continueAnimation |= tw->animate (0); + + if (continueAnimation) + mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK; + + priv->gScreen->glPaintOutput (attrib, matrix, region, output, mask); + + /* continueAnimation means that there are scaled windows + * around so we need to allow painting with custom vertex + * layouts */ + for (TileLayer::Ptr p : priv->mTileLayers) + { + bool animationsPending = p->animate (0); + + if (animationsPending) + p->paintOutline (matrix); + + continueAnimation |= animationsPending; + } +} + +void +TilesScreen::donePaint () +{ + for (TileLayer::Ptr p : priv->mTileLayers) + { + if (p->animate (0)) + p->damage (); + } + + for (TilesWindow *tw : priv->mDraggedWindows) + { + if (tw->animate (0)) + tw->damage (); + } +} + +TilesWindow::TilesWindow (CompWindow *w) : + PluginClassHandler <TilesWindow, CompWindow> (w), + priv (new PrivateTilesWindow) +{ + priv->window = w; + priv->cWindow = CompositeWindow::get (w); + priv->gWindow = GLWindow::get (w); + + WindowInterface::setHandler (priv->window); + CompositeWindowInterface::setHandler (priv->cWindow); + GLWindowInterface::setHandler (priv->gWindow); +} + +TilesWindow::~TilesWindow () +{ +} + +TilesScreen::~TilesScreen () +{ + delete priv; +} + +TilesScreen::TilesScreen (CompScreen *s) : + PluginClassHandler <TilesScreen, CompScreen> (s), + priv (new PrivateTilesScreen) +{ + priv->cScreen = CompositeScreen::get (screen); + priv->gScreen = GLScreen::get (screen); + + ScreenInterface::setHandler (screen); + CompositeScreenInterface::setHandler (priv->cScreen); + GLScreenInterface::setHandler (priv->gScreen); +} + + +bool +TilesPluginVTable::init () +{ + if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION) || + !CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI) || + !CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI)) + { + return false; + } + + return true; +} diff --git a/src/tiles.h b/src/tiles.h new file mode 100644 index 0000000..2f0028c --- /dev/null +++ b/src/tiles.h @@ -0,0 +1,245 @@ +/* + * Compiz Tiles Plugin + * + * tiles.h + * + * Copyright (c) 2011 Sam Spilsbury <smspillaz@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 3 + * 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. + */ + +#include <core/core.h> +#include <composite/composite.h> +#include <opengl/opengl.h> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <unordered_map> +#include <hash_fun.h> + +#include "tiles_options.h" + +class TileLayer; +typedef boost::shared_ptr <TileLayer> TileLayerPtr; + +namespace RectMap +{ + class Hash { + public: + bool operator() (const CompRect &r) const + { + std::hash <int> h; + + return h (r.area ()); + } + }; + + class Predicate { + public: + bool operator() (const CompRect &a, const CompRect &b) const + { + return (a == b); + } + }; + + typedef std::unordered_map<CompRect, CompRect, Hash, Predicate> Map; +} + +class PrivateTile +{ + public: + + TileLayerPtr mParent; + CompRect mRect; + CompWindow *mWindow; + CompWindow::Geometry mSaveGeometry; + unsigned int mSaveMask; + CompPoint mDragBuffer; + float mProgress; +}; + +class Tile : + public boost::enable_shared_from_this<Tile> +{ + public: + + Tile (TileLayerPtr parent); + ~Tile (); + + /* Target size */ + CompRect rect (); + CompWindow * window (); + GLVector scale (); + + /* Returns false if window cannot be put + * in this tile's allocation */ + bool allocateWindow (CompWindow *); + + /* setTargetSize will allocate a new target size + * for this tile, which will be animated to, while + * lockTargetSize actually resizes the window to that + * size */ + bool setTargetSize (CompRect &); + void lockTargetSize (); + + void resized (CompRect &); + + bool animate (unsigned int ms); + void damage (); + + void grab (); + bool drag (CompPoint &p); + void ungrab (); + + typedef boost::shared_ptr<Tile> Ptr; + private: + + PrivateTile *priv; +}; + +class PrivateTileLayer +{ + public: + + void pushSpace (CompRect r); + void popSpaces (); + + std::vector<Tile::Ptr> mTiles; + CompRegion mDropZones; + CompOutput *mOutput; + RectMap::Map mPushedSpaces; + CompPoint mLastPointer; +}; + +class TileLayer : + public boost::enable_shared_from_this <TileLayer> +{ + public: + + TileLayer (CompOutput *output); + virtual ~TileLayer (); + + const std::vector<Tile::Ptr> & tiles (); + + void handleWindowResize (CompWindow *); + void handleWindowGrabbed (CompWindow *w); + void handleWindowGrabMovement (CompWindow *w, CompPoint &p); + void handleWindowUngrabbed (CompWindow *w); + + bool addWindow (CompWindow *w, CompRect &); + void removeWindow (CompWindow *w); + void paintOutline (const GLMatrix &); + + bool animate (unsigned int ms); + void damage (); + + typedef TileLayerPtr Ptr; + + protected: + + bool tilesToRegion (std::vector <Tile::Ptr> tiles, + CompRegion tilesRegion, + CompRegion nextRegion); + + private: + + PrivateTileLayer *priv; +}; + +class PrivateTilesWindow +{ + public: + CompWindow *window; + CompositeWindow *cWindow; + GLWindow *gWindow; + + Tile::Ptr mTile; +}; + +class TilesWindow : + public PluginClassHandler <TilesWindow, CompWindow>, + public WindowInterface, + public CompositeWindowInterface, + public GLWindowInterface +{ + public: + + TilesWindow (CompWindow *w); + ~TilesWindow (); + + void grabNotify (int x, int y, unsigned int state, unsigned int mask); + void ungrabNotify (); + + void moveNotify (int dx, int dy, bool immediate); + void validateResizeRequest (unsigned int &mask, + XWindowChanges *xwc, + unsigned int source); + void resizeNotify (int dx, int dy, int dwidth, int dheight); + + bool glPaint (const GLWindowPaintAttrib &attrib, const GLMatrix &matrix, + const CompRegion ®ion, unsigned int mask); + bool damageRect (bool initial, const CompRect &rect); + + bool animate (unsigned int ms); + + void damage (); + + CompWindow * window () { return priv->window; } // XXX + + private: + + PrivateTilesWindow *priv; +}; + +class PrivateTilesScreen +{ + public: + + CompositeScreen *cScreen; + GLScreen *gScreen; + + std::vector <TilesWindow *> mDraggedWindows; + std::vector <TileLayer::Ptr> mTileLayers; +}; + +class TilesScreen : + public PluginClassHandler <TilesScreen, CompScreen>, + public ScreenInterface, + public CompositeScreenInterface, + public GLScreenInterface, + public TilesOptions +{ + public: + + TilesScreen (CompScreen *); + ~TilesScreen (); + + void preparePaint (int); + bool glPaintOutput (const GLScreenPaintAttrib &attrib, const GLMatrix &matrix, + const CompRegion ®ion, CompOutput *output, unsigned int mask); + void donePaint (); + + void addGrabbedWindow (TilesWindow *tw); + void removeGrabbedWindow (TilesWindow *tw); + void dragGrabbedWindow (TilesWindow *tw, CompPoint pointer); + bool grabbedWindows (); + + private: + + PrivateTilesScreen *priv; +}; + +class TilesPluginVTable : + public CompPlugin::VTableForScreenAndWindow<TilesScreen, TilesWindow> +{ + public: + + bool init (); +}; diff --git a/tiles.xml.in b/tiles.xml.in new file mode 100644 index 0000000..5672444 --- /dev/null +++ b/tiles.xml.in @@ -0,0 +1,7 @@ +<compiz> + <plugin name="tiles" useBcop="true"> + <_short>Tiles</_short> + <_long>Window Tiles</_long> + <category>Window Management</category> + </plugin> +</compiz> |