diff options
-rw-r--r-- | src/tiles.cpp | 249 | ||||
-rw-r--r-- | src/tiles.h | 12 |
2 files changed, 206 insertions, 55 deletions
diff --git a/src/tiles.cpp b/src/tiles.cpp index 5873ae1..86b279f 100644 --- a/src/tiles.cpp +++ b/src/tiles.cpp @@ -33,12 +33,17 @@ Tile::~Tile() if (priv->mWindow) { XWindowChanges xwc; - xwc.x = priv->mSaveGeometry.x (); - xwc.y = priv->mSaveGeometry.y (); + float xScale, yScale; + + xScale = priv->mSaveGeometry.width () / static_cast <float> (priv->mWindow->geometry ().width ()); + yScale = priv->mSaveGeometry.height () / static_cast <float> (priv->mWindow->geometry ().height ()); + + xwc.x = pointerX - ((pointerX - priv->mWindow->geometry ().x ()) * xScale); + xwc.y = pointerY - ((pointerY - priv->mWindow->geometry ().y ()) * yScale); xwc.width = priv->mSaveGeometry.width (); xwc.height = priv->mSaveGeometry.height (); - priv->mWindow->configureXWindow (priv->mSaveMask, &xwc); + priv->mWindow->configureXWindow (priv->mSaveMask | CWX | CWY, &xwc); } delete priv; @@ -64,7 +69,7 @@ Tile::allocateWindow (CompWindow *w) priv->mWindow = w; priv->mSaveGeometry = priv->mWindow->serverGeometry (); - priv->mSaveMask = CWX | CWY | CWWidth | CWHeight; + priv->mSaveMask = CWWidth | CWHeight; return true; } @@ -88,6 +93,7 @@ Tile::animate (unsigned int ms) void Tile::lockTargetSize() { + priv->mRect = priv->mTarget; CompRect resizeTarget = priv->mRect; resized (resizeTarget); @@ -131,7 +137,7 @@ Tile::scale () bool Tile::setTargetSize (CompRect &r) { - priv->mRect = r; + priv->mTarget = r; return true; } @@ -142,24 +148,63 @@ TileLayer::tiles () } void -TileLayer::handleWindowResize (CompWindow *output) +TileLayer::handleWindowResize (CompWindow *window, int x, int y, int width, int height) { - 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 */ + std::vector <Tile::Ptr>::iterator tpit = priv->mTiles.begin (); - for (Tile::Ptr t : priv->mTiles) + for (; tpit != priv->mTiles.end (); tpit++) { - available -= t->rect (); + if ((*tpit)->window ()->id () == window->id ()) + { + break; + } } - /* Search tiles for available space, resize where possible */ - for (const CompRect &r : available.rects ()) + if (tpit != priv->mTiles.end ()) { + Tile::Ptr rtp = *tpit; + CompRegion reg = CompRegion (x - window->border ().left, + y - window->border ().top, + width + (window->border ().left + window->border ().right), + height + (window->border ().top + window->border ().bottom)); + CompRect r = reg.boundingRect (); + CompRect old = rtp->rect (); + + /* Allocate a new space for this window + * and change the target size of other windows */ + if (!rtp->setTargetSize (r)) + return; + + CompRegion insertRegion = reg; + CompRegion intersectingTilesRegion; + std::vector <Tile::Ptr> intersectingTiles; + + insertRegion += CompRegion (r.x2 (), r.y (), priv->mOutput->workArea ().width () - r.x2 (), r.height ()); + insertRegion += CompRegion (r.x (), r.y2 (), r.width (), priv->mOutput->workArea ().height () - 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 reallocate the other tiles that intersect this one */ + for (Tile::Ptr tp : priv->mTiles) + { + if (tp == rtp) + { + intersectingTilesRegion += old; + continue; + } + + if ((CompRegion (tp->rect ()).intersected (insertRegion)) == CompRegion (tp->rect ())) + { + intersectingTiles.push_back (tp); + intersectingTilesRegion += tp->rect (); + } + } + + CompRegion allowedRegion = intersectingTilesRegion - r; + intersectingTilesRegion -= old; + + if (!tilesToRegion (intersectingTiles, intersectingTilesRegion, allowedRegion)) + return; } } @@ -197,7 +242,7 @@ TileLayer::handleWindowGrabbed (CompWindow *w) { priv->mPushedSpaces.clear(); - /* Recalculate drop zones */ + /* Recalculate drop zones if (tiles ().empty ()) { priv->mDropZones = CompRegion (*priv->mOutput) - @@ -212,7 +257,11 @@ TileLayer::handleWindowGrabbed (CompWindow *w) 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->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); priv->mLastPointer = CompPoint (pointerX, pointerY); } @@ -410,17 +459,45 @@ TileLayer::tilesToRegion (std::vector <Tile::Ptr> tiles, float yScale = nextRegion.boundingRect ().height () / static_cast <float> (tilesRegion.boundingRect ().height ()); CompPoint pos = tp->rect ().pos () - tilesRegion.boundingRect ().pos (); + + float width = tp->rect ().width () * xScale; + float height = tp->rect ().height () * yScale; + float x = pos.x () * xScale; + float y = pos.y () * yScale; + + if (xScale >= 1.0f) + { + width = ceil (width); + x = ceil (x); + } + else + { + width = floor (width); + x = floor (x); + } + + if (yScale >= 1.0f) + { + height = ceil (height); + y = ceil (y); + } + else + { + height = floor (height); + y = floor (y); + } + CompRect nextPosition; /* Scale the new positions */ - pos.setX (pos.x () * xScale); - pos.setY (pos.y () * yScale); + pos.setX (x); + pos.setY (y); pos += nextRegion.boundingRect ().pos (); /* Now scale the sizes */ - nextPosition.setWidth (tp->rect ().width () * xScale); - nextPosition.setHeight (tp->rect ().height () * yScale); + nextPosition.setWidth (width); + nextPosition.setHeight (height); nextPosition.setPos (pos); @@ -451,7 +528,7 @@ TileLayer::addWindow (CompWindow *w, CompRect &r) * | | | | * | | | | * | | | | - * |----------|-----------------------| + * ------------------------------------ * | | * | | * | | @@ -460,12 +537,11 @@ TileLayer::addWindow (CompWindow *w, CompRect &r) * ------------- */ - 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 (r.x2 (), r.y (), priv->mOutput->workArea ().width () - r.x2 (), r.height ()); + insertRegion += CompRegion (r.x (), r.y2 (), r.width (), priv->mOutput->workArea ().height () - 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; @@ -477,7 +553,7 @@ TileLayer::addWindow (CompWindow *w, CompRect &r) /* Now reallocate the other tiles that intersect this one */ for (Tile::Ptr tp : priv->mTiles) { - if (CompRegion (tp->rect ()).intersects (insertRegion)) + if ((CompRegion (tp->rect ()) - insertRegion).isEmpty ()) { intersectingTiles.push_back (tp); intersectingTilesRegion += tp->rect (); @@ -526,8 +602,8 @@ TileLayer::removeWindow (CompWindow *w) 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 (r.x2 (), r.y (), priv->mOutput->workArea ().width () - r.x2 (), r.height ()); + insertRegion += CompRegion (r.x (), r.y2 (), r.width (), priv->mOutput->workArea ().height () - 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 ()); @@ -618,12 +694,15 @@ TileLayer::~TileLayer () void TilesWindow::grabNotify (int x, int y, unsigned int state, unsigned int mask) { - if (mask & (CompWindowGrabMoveMask | CompWindowGrabButtonMask)) + if (mask & (CompWindowGrabMoveMask)) { if (!priv->mTile) priv->window->moveNotifySetEnabled (this, true); TilesScreen::get (screen)->addGrabbedWindow (this); } + else if (mask & (CompWindowGrabResizeMask) && + priv->mTile) + TilesScreen::get (screen)->addResizingWindow (this); priv->window->grabNotify (x, y, state, mask); } @@ -648,18 +727,6 @@ TilesWindow::moveNotify (int dx, int dy, bool 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) @@ -762,7 +829,10 @@ TilesWindow::damageRect (bool initial, const CompRect &rect) bool TilesWindow::animate(unsigned int ms) { - return priv->mTile->animate (ms); + if (priv->mTile) + return priv->mTile->animate (ms); + else + return false; } void @@ -772,6 +842,17 @@ TilesWindow::damage () } void +TilesScreen::handleWindowResized (TilesWindow *tw, int x, int y, int width, int height) +{ + if (priv->mTileLayers.size ()) + { + TileLayer::Ptr tp = priv->mTileLayers.front (); // assuming here that there is a tileLayer since there is a tile + + tp->handleWindowResize (tw->window (), x, y, width, height); + } +} + +void TilesScreen::dragGrabbedWindow (TilesWindow *tw, CompPoint pointer) { if (priv->mTileLayers.size ()) @@ -784,17 +865,79 @@ 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 ()); + 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 (); + } + else + { + auto rit = std::find (priv->mResizedWindows.begin (), priv->mResizedWindows.end (), tw); + + if (rit != priv->mResizedWindows.end ()) + priv->mResizedWindows.erase (rit); + + if (priv->mResizedWindows.empty ()) + { + for (const Tile::Ptr &tp : priv->mTileLayers.front ()->tiles ()) + tp->lockTargetSize (); + } + } +} + +void +TilesScreen::handleEvent (XEvent *event) +{ + CompWindow *w = NULL; + + switch (event->type) + { + case ClientMessage: + + w = screen->findWindow (event->xproperty.window); - /* No more dragged windows and the last tile layer is empty, - * delete it */ + if (w) + { + if (event->xclient.message_type == XInternAtom (screen->dpy (), "_COMPIZ_RESIZE_NOTIFY", 0)) + { + TilesScreen::get (screen)->handleWindowResized (TilesWindow::get (w), + static_cast <int> (event->xclient.data.l[0]), + static_cast <int> (event->xclient.data.l[1]), + static_cast <int> (event->xclient.data.l[2]), + static_cast <int> (event->xclient.data.l[3])); + } + } + } - if (priv->mTileLayers.size () == 1) - if (priv->mTileLayers.front ()->tiles ().empty ()) - priv->mTileLayers.clear (); + screen->handleEvent (event); +} + +bool +TilesScreen::grabbedWindows (unsigned int mask) +{ + bool ret = false; + + if (mask & CompWindowGrabMoveMask) + ret |= !priv->mDraggedWindows.empty (); + + if (mask & CompWindowGrabResizeMask) + ret |= !priv->mResizedWindows.empty (); + + return ret; +} + +void +TilesScreen::addResizingWindow (TilesWindow *tw) +{ + priv->mResizedWindows.push_back (tw); } void @@ -813,8 +956,10 @@ TilesScreen::addGrabbedWindow (TilesWindow *tw) tp = priv->mTileLayers.back (); if (std::find (priv->mDraggedWindows.begin (), priv->mDraggedWindows.end (), tw) - != priv->mDraggedWindows.end ()) + == priv->mDraggedWindows.end ()) + { priv->mDraggedWindows.push_back (tw); + } tp->handleWindowGrabbed (tw->window ()); diff --git a/src/tiles.h b/src/tiles.h index 2f0028c..0d30bb6 100644 --- a/src/tiles.h +++ b/src/tiles.h @@ -58,6 +58,7 @@ class PrivateTile TileLayerPtr mParent; CompRect mRect; + CompRect mTarget; CompWindow *mWindow; CompWindow::Geometry mSaveGeometry; unsigned int mSaveMask; @@ -128,7 +129,7 @@ class TileLayer : const std::vector<Tile::Ptr> & tiles (); - void handleWindowResize (CompWindow *); + void handleWindowResize (CompWindow *, int x, int y, int width, int height); void handleWindowGrabbed (CompWindow *w); void handleWindowGrabMovement (CompWindow *w, CompPoint &p); void handleWindowUngrabbed (CompWindow *w); @@ -181,7 +182,7 @@ class TilesWindow : void validateResizeRequest (unsigned int &mask, XWindowChanges *xwc, unsigned int source); - void resizeNotify (int dx, int dy, int dwidth, int dheight); + void onResizeNotification (int x, int y, int width, int height); bool glPaint (const GLWindowPaintAttrib &attrib, const GLMatrix &matrix, const CompRegion ®ion, unsigned int mask); @@ -206,6 +207,7 @@ class PrivateTilesScreen GLScreen *gScreen; std::vector <TilesWindow *> mDraggedWindows; + std::vector <TilesWindow *> mResizedWindows; std::vector <TileLayer::Ptr> mTileLayers; }; @@ -228,8 +230,12 @@ class TilesScreen : void addGrabbedWindow (TilesWindow *tw); void removeGrabbedWindow (TilesWindow *tw); + void addResizingWindow (TilesWindow *tw); void dragGrabbedWindow (TilesWindow *tw, CompPoint pointer); - bool grabbedWindows (); + void handleWindowResized (TilesWindow *tw, int x, int y, int width, int height); + bool grabbedWindows (unsigned int); + + void handleEvent (XEvent *event); private: |