summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEduardo Gurgel Pinho <eduardo@mad4.Chagas>2009-02-16 22:35:44 -0300
committerEduardo Gurgel Pinho <eduardo@mad4.Chagas>2009-02-16 22:35:44 -0300
commit075bbdb25419f3564282dbf098baa8a52499b2a9 (patch)
treeef01b153f78a4c532a2ee30b0fe036748a76b1a5
parentbef606a4889b9d77d48a328ff1ff475967ba2d43 (diff)
downloadput-075bbdb25419f3564282dbf098baa8a52499b2a9.tar.gz
put-075bbdb25419f3564282dbf098baa8a52499b2a9.tar.bz2
Compiz++ port.
-rw-r--r--put.cpp1270
-rw-r--r--put.h220
2 files changed, 1490 insertions, 0 deletions
diff --git a/put.cpp b/put.cpp
new file mode 100644
index 0000000..6df5a4e
--- /dev/null
+++ b/put.cpp
@@ -0,0 +1,1270 @@
+/*
+ * Copyright (c) 2006 Darryll Truchan <moppsy@comcast.net>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "put.h"
+
+#include <cmath>
+#include <cstring>
+#include <iostream>
+
+#define PUT_ONLY_EMPTY(type) (type >= PutEmptyBottomLeft && type <= PutEmptyTopRight)
+
+
+/*
+ * Maximumize functions
+ * Functions are from Maximumize plugin (Author:Kristian LyngstĂžl <kristian@bohemians.org>)
+ */
+
+/* Generates a region containing free space (here the
+ * active window counts as free space). The region argument
+ * is the start-region (ie: the output dev).
+ * Logic borrowed from opacify (courtesy of myself).
+ */
+Region
+PutScreen::emptyRegion (CompWindow *window,
+ Region region)
+{
+ Region newRegion, tmpRegion;
+ XRectangle tmpRect;
+
+ newRegion = XCreateRegion ();
+ if (!newRegion)
+ return NULL;
+
+ tmpRegion = XCreateRegion ();
+ if (!tmpRegion)
+ {
+ XDestroyRegion (newRegion);
+ return NULL;
+ }
+
+ XUnionRegion (region, newRegion, newRegion);
+
+ foreach(CompWindow *w, screen->windows ())
+ {
+ EMPTY_REGION (tmpRegion);
+ if (w->id () == window->id ())
+ continue;
+
+ if (w->invisible () || /*w->hidden () ||*/ w->minimized ())
+ continue;
+
+ if (w->wmType () & CompWindowTypeDesktopMask)
+ continue;
+
+ if (w->wmType () & CompWindowTypeDockMask)
+ {
+ if (w->struts ())
+ {
+ XUnionRectWithRegion (&w->struts ()->left, tmpRegion, tmpRegion);
+ XUnionRectWithRegion (&w->struts ()->right, tmpRegion, tmpRegion);
+ XUnionRectWithRegion (&w->struts ()->top, tmpRegion, tmpRegion);
+ XUnionRectWithRegion (&w->struts ()->bottom, tmpRegion, tmpRegion);
+ XSubtractRegion (newRegion, tmpRegion, newRegion);
+ }
+ continue;
+ }
+
+
+ tmpRect.x = w->serverX () - w->input().left;
+ tmpRect.y = w->serverY () - w->input().top;
+ tmpRect.width = w->serverWidth () + w->input ().right + w->input ().left;
+ tmpRect.height = w->serverHeight () + w->input ().top +
+ w->input ().bottom;
+
+ XUnionRectWithRegion (&tmpRect, tmpRegion, tmpRegion);
+ XSubtractRegion (newRegion, tmpRegion, newRegion);
+ }
+
+ XDestroyRegion (tmpRegion);
+
+ return newRegion;
+}
+
+/* Returns true if box a has a larger area than box b.
+ */
+bool
+PutScreen::boxCompare (BOX a,
+ BOX b)
+{
+ int areaA, areaB;
+
+ areaA = (a.x2 - a.x1) * (a.y2 - a.y1);
+ areaB = (b.x2 - b.x1) * (b.y2 - b.y1);
+
+ return (areaA > areaB);
+}
+
+/* Extends the given box for Window w to fit as much space in region r.
+ * If XFirst is true, it will first expand in the X direction,
+ * then Y. This is because it gives different results.
+ * PS: Decorations are icky.
+ */
+BOX
+PutScreen::extendBox (CompWindow *w,
+ BOX tmp,
+ Region r,
+ bool xFirst,
+ bool left,
+ bool right,
+ bool up,
+ bool down)
+{
+ short int counter = 0;
+ Bool touch = false;
+
+#define CHECKREC \
+ XRectInRegion (r, tmp.x1 - w->input ().left, tmp.y1 - w->input ().top,\
+ tmp.x2 - tmp.x1 + w->input ().left + w->input ().right,\
+ tmp.y2 - tmp.y1 + w->input ().top + w->input ().bottom)\
+ == RectangleIn
+
+ while (counter < 1)
+ {
+ if ((xFirst && counter == 0) || (!xFirst && counter == 1))
+ {
+ if(left) {
+ while (CHECKREC) {
+ tmp.x1--;
+ touch = true;
+ }
+ if (touch) tmp.x1++;
+ }
+ touch = false;
+
+ if(right) {
+ while (CHECKREC) {
+ tmp.x2++;
+ touch = true;
+ }
+ if (touch) tmp.x2--;
+ }
+ touch = false;
+ counter++;
+ }
+
+ if ((xFirst && counter == 1) || (!xFirst && counter == 0))
+ {
+ if(down) {
+ while (CHECKREC) {
+ tmp.y2++;
+ touch = true;
+ }
+ if (touch) tmp.y2--;
+ }
+ touch = false;
+
+ if(up) {
+ while (CHECKREC) {
+ tmp.y1--;
+ touch = true;
+ }
+ if (touch) tmp.y1++;
+ }
+ touch = false;
+ counter++;
+ }
+ }
+#undef CHECKREC
+ return tmp;
+}
+
+/* Create a box for resizing in the given region
+ * Also shrinks the window box in case of minor overlaps.
+ * FIXME: should be somewhat cleaner.
+ */
+BOX
+PutScreen::findRect (CompWindow *w,
+ Region r,
+ bool left,
+ bool right,
+ bool up,
+ bool down)
+{
+ BOX windowBox, ansA, ansB, orig;
+
+ windowBox.x1 = w->serverX ();
+ windowBox.x2 = w->serverX () + w->serverWidth ();
+ windowBox.y1 = w->serverY ();
+ windowBox.y2 = w->serverY () + w->serverHeight ();
+
+ orig = windowBox;
+
+ ansA = extendBox (w, windowBox, r, true, left, right, up, down);
+ ansB = extendBox (w, windowBox, r, false, left, right, up, down);
+
+ if (boxCompare (orig, ansA) &&
+ boxCompare (orig, ansB))
+ return orig;
+ if (boxCompare (ansA, ansB))
+ return ansA;
+ else
+ return ansB;
+
+}
+
+/* Calls out to compute the resize */
+unsigned int
+PutScreen::computeResize(CompWindow *w,
+ XWindowChanges *xwc,
+ bool left,
+ bool right,
+ bool up,
+ bool down)
+{
+ CompOutput *output;
+ Region region;
+ unsigned int mask = 0;
+ BOX box;
+ int outputDevice = w->outputDevice ();
+
+
+ output = &screen->outputDevs ()[outputDevice];
+ region = emptyRegion (w, output->region ());
+ if (!region)
+ return mask;
+
+ box = findRect (w, region, left, right, up, down);
+ XDestroyRegion (region);
+
+ if (box.x1 != w->serverX ())
+ mask |= CWX;
+
+ if (box.y1 != w->serverY ())
+ mask |= CWY;
+
+ if ((box.x2 - box.x1) != w->serverWidth ())
+ mask |= CWWidth;
+
+ if ((box.y2 - box.y1) != w->height ())
+ mask |= CWHeight;
+
+ xwc->x = box.x1;
+ xwc->y = box.y1;
+ xwc->width = box.x2 - box.x1;
+ xwc->height = box.y2 - box.y1;
+
+ return mask;
+}
+
+
+/*
+ * End of Maximumize functions
+ */
+
+/*
+ * calculate the velocity for the moving window
+ */
+int
+PutScreen::adjustVelocity (CompWindow *w)
+{
+ float dx, dy, adjust, amount;
+ float x1, y1;
+
+ PUT_WINDOW (w);
+
+ x1 = pw->targetX;
+ y1 = pw->targetY;
+
+ dx = x1 - (w->x () + pw->tx);
+ dy = y1 - (w->y () + pw->ty);
+
+ adjust = dx * 0.15f;
+ amount = fabs (dx) * 1.5;
+ if (amount < 0.5f)
+ amount = 0.5f;
+ else if (amount > 5.0f)
+ amount = 5.0f;
+
+ pw->xVelocity = (amount * pw->xVelocity + adjust) / (amount + 1.0f);
+
+ adjust = dy * 0.15f;
+ amount = fabs (dy) * 1.5f;
+ if (amount < 0.5f)
+ amount = 0.5f;
+ else if (amount > 5.0f)
+ amount = 5.0f;
+
+ pw->yVelocity = (amount * pw->yVelocity + adjust) / (amount + 1.0f);
+
+ if (fabs (dx) < 0.1f && fabs (pw->xVelocity) < 0.2f &&
+ fabs (dy) < 0.1f && fabs (pw->yVelocity) < 0.2f)
+ {
+ /* animation done */
+ pw->xVelocity = pw->yVelocity = 0.0f;
+
+ pw->tx = x1 - w->x ();
+ pw->ty = y1 - w->y ();
+ return 0;
+ }
+ return 1;
+}
+
+void
+PutScreen::finishWindowMovement (CompWindow *w)
+{
+ PUT_WINDOW (w);
+
+ w->move (pw->targetX - w->x (),
+ pw->targetY - w->y (),
+ true);
+ w->syncPosition ();
+
+ if (w->state () & (MAXIMIZE_STATE | CompWindowStateFullscreenMask))
+ w->updateAttributes (CompStackingUpdateModeNone);
+}
+
+unsigned int
+PutScreen::getOutputForWindow (CompWindow *w)
+{
+ PUT_WINDOW (w);
+
+ if (!pw->adjust)
+ return w->outputDevice ();
+
+ /* outputDeviceForWindow uses the server geometry,
+ so specialcase a running animation, which didn't
+ apply the server geometry yet */
+ return screen->outputDeviceForGeometry (CompWindow::Geometry(
+ w->x () + pw->tx,
+ w->y () + pw->ty,
+ w->width (),
+ w->height (),
+ w->geometry ().border() ));
+}
+
+
+bool
+PutScreen::getDistance (CompWindow *w,
+ PutType type,
+ CompOption::Vector &option,
+ int *distX,
+ int *distY)
+{
+
+ CompScreen *s = screen;
+ int x, y, dx, dy, posX, posY;
+ int viewport, output;
+ XRectangle workArea;
+
+ PUT_SCREEN (s);
+ PUT_WINDOW (w);
+
+ posX = CompOption::getIntOptionNamed (option,"x", 0);
+ posY = CompOption::getIntOptionNamed (option,"y", 0);
+
+ /* get the output device number from the options list */
+ output = CompOption::getIntOptionNamed (option,"output", -1);
+ /* no output in options list -> use the current output */
+ if (output == -1)
+ {
+ /* no output given, so use the current output if
+ this wasn't a double tap */
+
+ if (ps->lastType != type || ps->lastWindow != w->id ())
+ output = getOutputForWindow (w);
+ }
+ else
+ {
+ /* make sure the output number is not out of bounds */
+ output = MIN (output, s->outputDevs ().size () - 1);
+ }
+
+ if (output == -1)
+ {
+ /* user double-tapped the key, so use the screen work area */
+ workArea = s->workArea ();
+ /* set the type to unknown to have a toggle-type behaviour
+ between 'use output work area' and 'use screen work area' */
+ ps->lastType = PutUnknown;
+ }
+ else
+ {
+ /* single tap or output provided via options list,
+ use the output work area */
+ s->getWorkareaForOutput (output, &workArea);
+ ps->lastType = type;
+ }
+
+ if(PUT_ONLY_EMPTY(type))
+ {
+ unsigned int mask;
+ XWindowChanges xwc;
+ bool left, right, up, down;
+ left = right = up = down = false;
+ switch(type) {
+ case PutEmptyBottomLeft:
+ left = down = true;
+ break;
+ case PutEmptyBottom:
+ down = true;
+ break;
+ case PutEmptyBottomRight:
+ right = down = true;
+ break;
+ case PutEmptyLeft:
+ left = true;
+ break;
+ case PutEmptyCenter:
+ left = right = up = down = true;
+ break;
+ case PutEmptyRight:
+ right = true;
+ break;
+ case PutEmptyTopLeft:
+ left = up = true;
+ break;
+ case PutEmptyTop:
+ up = true;
+ break;
+ case PutEmptyTopRight:
+ right = up = true;
+ break;
+ default:
+ left = right = up = down = false;
+ }
+ mask = computeResize (w, &xwc, left,right,up,down);
+ if (mask)
+ {
+ int width_, height_;
+ if (w->constrainNewWindowSize ( xwc.width, xwc.height,
+ &width_, &height_))
+ {
+ mask |= CWWidth | CWHeight;
+ xwc.width = width_;
+ xwc.height = height_;
+ }
+ }
+ workArea.width = xwc.width;
+ workArea.height = xwc.height;
+ workArea.x = xwc.x;
+ workArea.y = xwc.y;
+ }
+ /* the windows location */
+ x = w->x () + pw->tx;
+ y = w->y () + pw->ty;
+
+ switch (type) {
+ case PutEmptyCenter:
+ case PutCenter:
+ /* center of the screen */
+ dx = (workArea.width / 2) - (w->serverWidth () / 2) - (x - workArea.x);
+ dy = (workArea.height / 2) - (w->serverHeight () / 2) - (y - workArea.y);
+ break;
+ case PutLeft:
+ /* center of the left edge */
+ dx = -(x - workArea.x) + w->input().left + ps->optionGetPadLeft ();
+ dy = (workArea.height / 2) - (w->serverHeight () / 2) - (y - workArea.y);
+ break;
+ case PutEmptyLeft:
+ /* center of the left edge */
+ workArea.x -= w->input().left;
+ dx = -(x - workArea.x) + w->input().left + ps->optionGetPadLeft ();
+ dy = (workArea.height / 2) - (w->serverHeight () / 2) - (y - workArea.y);
+ break;
+ case PutTopLeft:
+ /* top left corner */
+ dx = -(x - workArea.x) + w->input().left + ps->optionGetPadLeft ();
+ dy = -(y - workArea.y) + w->input().top + ps->optionGetPadTop ();
+ break;
+ case PutEmptyTopLeft:
+ /* top left corner */
+ workArea.y -= w->input().top;
+ workArea.x -= w->input().left;
+ dx = -(x - workArea.x) + w->input().left + ps->optionGetPadLeft ();
+ dy = -(y - workArea.y) + w->input().top + ps->optionGetPadTop ();
+ break;
+ case PutTop:
+ /* center of top edge */
+ dx = (workArea.width / 2) - (w->serverWidth () / 2) - (x - workArea.x);
+ dy = -(y - workArea.y) + w->input().top + ps->optionGetPadTop ();
+ break;
+ case PutEmptyTop:
+ /* center of top edge */
+ workArea.y -= w->input().top;
+ dx = (workArea.width / 2) - (w->serverWidth () / 2) - (x - workArea.x);
+ dy = -(y - workArea.y) + w->input().top + ps->optionGetPadTop ();
+ break;
+ case PutTopRight:
+ /* top right corner */
+ dx = workArea.width - w->serverWidth () - (x - workArea.x) -
+ w->input().right - ps->optionGetPadRight ();
+ dy = -(y - workArea.y) + w->input().top + ps->optionGetPadTop ();
+ break;
+ case PutEmptyTopRight:
+ /* top right corner */
+ workArea.y -= w->input().top;
+ workArea.x += w->input().right;
+ dx = workArea.width - w->serverWidth () - (x - workArea.x) -
+ w->input().right - ps->optionGetPadRight ();
+ dy = -(y - workArea.y) + w->input().top + ps->optionGetPadTop ();
+ break;
+ case PutRight:
+ /* center of right edge */
+ dx = workArea.width - w->serverWidth () - (x - workArea.x) -
+ w->input().right - ps->optionGetPadRight ();
+ dy = (workArea.height / 2) - (w->serverHeight () / 2) - (y - workArea.y);
+ break;
+ case PutEmptyRight:
+ /* center of right edge */
+ workArea.x += w->input().right;
+ dx = workArea.width - w->serverWidth () - (x - workArea.x) -
+ w->input().right - ps->optionGetPadRight ();
+ dy = (workArea.height / 2) - (w->serverHeight () / 2) - (y - workArea.y);
+ break;
+ case PutBottomRight:
+ /* bottom right corner */
+ dx = workArea.width - w->serverWidth () - (x - workArea.x) -
+ w->input().right - ps->optionGetPadRight ();
+ dy = workArea.height - w->serverHeight () - (y - workArea.y) -
+ w->input().bottom - ps->optionGetPadBottom ();
+ break;
+ case PutEmptyBottomRight:
+ /* bottom right corner */
+ workArea.y += w->input().bottom;
+ workArea.x += w->input().right;
+ dx = workArea.width - w->serverWidth () - (x - workArea.x) -
+ w->input().right - ps->optionGetPadRight ();
+ dy = workArea.height - w->serverHeight () - (y - workArea.y) -
+ w->input().bottom - ps->optionGetPadBottom ();
+ break;
+ case PutBottom:
+ /* center of bottom edge */
+ dx = (workArea.width / 2) - (w->serverWidth () / 2) - (x - workArea.x);
+ dy = workArea.height - w->serverHeight () - (y - workArea.y) -
+ w->input().bottom - ps->optionGetPadBottom ();
+ break;
+ case PutEmptyBottom:
+ /* center of bottom edge */
+ workArea.y += w->input().bottom;
+ dx = (workArea.width / 2) - (w->serverWidth () / 2) - (x - workArea.x);
+ dy = workArea.height - w->serverHeight () - (y - workArea.y) -
+ w->input().bottom - ps->optionGetPadBottom ();
+ break;
+ case PutBottomLeft:
+ /* bottom left corner */
+ dx = -(x - workArea.x) + w->input().left + ps->optionGetPadLeft ();
+ dy = workArea.height - w->serverHeight () - (y - workArea.y) -
+ w->input().bottom - ps->optionGetPadBottom ();
+ break;
+ case PutEmptyBottomLeft:
+ /* bottom left corner */
+ workArea.y += w->input().bottom;
+ workArea.x -= w->input().left;
+ dx = -(x - workArea.x) + w->input().left + ps->optionGetPadLeft ();
+ dy = workArea.height - w->serverHeight () - (y - workArea.y) -
+ w->input().bottom - ps->optionGetPadBottom ();
+ break;
+ case PutRestore:
+ /* back to last position */
+ dx = pw->lastX - x;
+ dy = pw->lastY - y;
+ break;
+ case PutViewport:
+ {
+ int vpX, vpY, hDirection, vDirection;
+
+ /* get the viewport to move to from the options list */
+ viewport = CompOption::getIntOptionNamed (option, "viewport", -1);
+
+ /* if viewport wasn't supplied, bail out */
+ if (viewport < 0)
+ return false;
+
+ /* split 1D viewport value into 2D x and y viewport */
+ vpX = viewport % s->vpSize ().width ();
+ vpY = viewport / s->vpSize ().height () ;
+ if (vpY > s->vpSize ().width ())
+ vpY = s->vpSize ().width () - 1;
+
+ /* take the shortest horizontal path to the destination viewport */
+ hDirection = (vpX - s->vp ().x ());
+ if (hDirection > s->vpSize ().height () / 2)
+ hDirection = (hDirection - s->vpSize ().height ());
+ else if (hDirection < -s->vpSize ().height () / 2)
+ hDirection = (hDirection + s->vpSize ().height ());
+
+ /* we need to do this for the vertical destination viewport too */
+ vDirection = (vpY - s->vp ().y ());
+ if (vDirection > s->vpSize ().width () / 2)
+ vDirection = (vDirection - s->vpSize ().width ());
+ else if (vDirection < -s->vpSize ().width () / 2)
+ vDirection = (vDirection + s->vpSize ().width ());
+
+ dx = s->width () * hDirection;
+ dy = s->height () * vDirection;
+ break;
+ }
+ case PutViewportLeft:
+ /* move to the viewport on the left */
+ dx = -s->width ();
+ dy = 0;
+ break;
+ case PutViewportRight:
+ /* move to the viewport on the right */
+ dx = s->width ();
+ dy = 0;
+ break;
+ case PutViewportUp:
+ /* move to the viewport above */
+ dx = 0;
+ dy = -s->height ();
+ break;
+ case PutViewportDown:
+ /* move to the viewport below */
+ dx = 0;
+ dy = s->height ();
+ break;
+ case PutNextOutput:
+ {
+ int outputNum, currentNum;
+ int nOutputDev = s->outputDevs ().size ();
+ CompOutput *currentOutput, *newOutput;
+
+ if (nOutputDev < 2)
+ return false;
+
+ currentNum = getOutputForWindow (w);
+ outputNum = (currentNum + 1) % nOutputDev;
+ outputNum = CompOption::getIntOptionNamed (option,"output", outputNum);
+
+ if (outputNum >= nOutputDev)
+ return false;
+
+ currentOutput = &s->outputDevs ().at(currentNum);
+ newOutput = &s->outputDevs ().at(outputNum);
+
+ /* move by the distance of the output center points */
+ dx = (newOutput->x1 () + newOutput->width () / 2) -
+ (currentOutput->x1 () + currentOutput->width () / 2);
+ dy = (newOutput->y1 () + newOutput->height () / 2) -
+ (currentOutput->y1 () + currentOutput->height () / 2);
+
+ /* update work area for new output */
+ workArea = newOutput->workArea ();
+ }
+ break;
+ case PutAbsolute:
+ /* move the window to an exact position */
+ if (posX < 0)
+ /* account for a specified negative position,
+ like geometry without (-0) */
+ dx = posX + s->width () - w->serverWidth () - x - w->input().right;
+ else
+ dx = posX - x + w->input().left;
+
+ if (posY < 0)
+ /* account for a specified negative position,
+ like geometry without (-0) */
+ dy = posY + s->height () - w->height () - y - w->input().bottom;
+ else
+ dy = posY - y + w->input().top;
+ break;
+ case PutRelative:
+ /* move window by offset */
+ dx = posX;
+ dy = posY;
+ break;
+ case PutPointer:
+ {
+ /* move the window to the pointers position
+ * using the current quad of the screen to determine
+ * which corner to move to the pointer
+ */
+ int rx, ry;
+ Window root, child;
+ int winX, winY;
+ unsigned int pMask;
+
+ /* get the pointers position from the X server */
+ if (XQueryPointer (s->dpy (), w->id (), &root, &child,
+ &rx, &ry, &winX, &winY, &pMask))
+ {
+ if (ps->optionGetWindowCenter ())
+ {
+ /* window center */
+ dx = rx - (w->serverWidth () / 2) - x;
+ dy = ry - (w->serverHeight () / 2) - y;
+ }
+ else if (rx < s->workArea ().width / 2 &&
+ ry < s->workArea ().height / 2)
+ {
+ /* top left quad */
+ dx = rx - x + w->input().left;
+ dy = ry - y + w->input().top;
+ }
+ else if (rx < s->workArea ().width / 2 &&
+ ry >= s->workArea ().height / 2)
+ {
+ /* bottom left quad */
+ dx = rx - x + w->input().left;
+ dy = ry - w->height () - y - w->input().bottom;
+ }
+ else if (rx >= s->workArea ().width / 2 &&
+ ry < s->workArea ().height / 2)
+ {
+ /* top right quad */
+ dx = rx - w->width () - x - w->input().right;
+ dy = ry - y + w->input().top;
+ }
+ else
+ {
+ /* bottom right quad */
+ dx = rx - w->width () - x - w->input().right;
+ dy = ry - w->height () - y - w->input().bottom;
+ }
+ }
+ else
+ {
+ dx = dy = 0;
+ }
+ }
+ break;
+ default:
+ /* if an unknown type is specified, do nothing */
+ dx = dy = 0;
+ break;
+ }
+
+ if ((dx || dy) && ps->optionGetAvoidOffscreen () &&
+ !(w->type () & CompWindowTypeFullscreenMask))
+ {
+ /* avoids window borders offscreen, but allow full
+ viewport movements */
+ int inDx, dxBefore;
+ int inDy, dyBefore;
+ CompWindowExtents extents, area;
+
+ inDx = dxBefore = dx % s->width ();
+ inDy = dyBefore = dy % s->height ();
+
+ extents.left = x + inDx - w->input().left;
+ extents.top = y + inDy - w->input().top;
+ extents.right = x + inDx + w->serverWidth () + w->input().right;
+ extents.bottom = y + inDy + w->serverHeight () + w->input().bottom;
+
+ area.left = workArea.x + ps->optionGetPadLeft ();
+ area.top = workArea.y + ps->optionGetPadTop ();
+ area.right = workArea.x + workArea.width - ps->optionGetPadRight ();
+ area.bottom = workArea.y + workArea.height - ps->optionGetPadBottom ();
+
+ if (extents.left < area.left)
+ inDx += area.left - extents.left;
+ else if (w->serverWidth () <= workArea.width && extents.right > area.right)
+ inDx += area.right - extents.right;
+
+ if (extents.top < area.top)
+ inDy += area.top - extents.top;
+ else if (w->serverHeight () <= workArea.height &&
+ extents.bottom > area.bottom)
+ inDy += area.bottom - extents.bottom;
+
+ /* apply the change */
+ dx += inDx - dxBefore;
+ dy += inDy - dyBefore;
+ }
+
+ *distX = dx;
+ *distY = dy;
+
+ return true;
+}
+
+void
+PutScreen::preparePaint (int ms)
+{
+
+ PUT_SCREEN (screen);
+
+ if (ps->moreAdjust && ps->grabIndex)
+ {
+ int steps;
+ float amount, chunk;
+
+ amount = ms * 0.025f * ps->optionGetSpeed ();
+ steps = amount / (0.5f * ps->optionGetTimestep ());
+ if (!steps)
+ steps = 1;
+ chunk = amount / (float)steps;
+
+ while (steps--)
+ {
+ Window endAnimationWindow = None;
+
+ ps->moreAdjust = 0;
+ foreach(CompWindow *w, screen->windows ())
+ {
+ PUT_WINDOW (w);
+
+ if (pw->adjust)
+ {
+ pw->adjust = adjustVelocity (w);
+ ps->moreAdjust |= pw->adjust;
+
+ pw->tx += pw->xVelocity * chunk;
+ pw->ty += pw->yVelocity * chunk;
+
+ if (!pw->adjust)
+ {
+ /* animation done */
+ finishWindowMovement (w);
+
+ if (w->id () == screen->activeWindow ())
+ endAnimationWindow = w->id ();
+
+ pw->tx = pw->ty = 0;
+ }
+ }
+ }
+ if (!ps->moreAdjust)
+ {
+ /* unfocus moved window if enabled */
+ if (ps->optionGetUnfocusWindow ())
+ screen->focusDefaultWindow ();
+ else if (endAnimationWindow)
+ screen->sendWindowActivationRequest (endAnimationWindow);
+ break;
+ }
+ }
+ }
+
+ cScreen->preparePaint (ms);
+}
+
+/* This is the guts of the paint function. You can transform the way the entire output is painted
+ * or you can just draw things on screen with openGL. The unsigned int here is a mask for painting
+ * the screen, see opengl/opengl.h on how you can change it */
+
+bool
+PutScreen::glPaintOutput (const GLScreenPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ CompOutput *output,
+ unsigned int mask)
+{
+ bool status;
+
+ PUT_SCREEN (screen);
+
+ if (ps->moreAdjust)
+ mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_MASK;
+
+ status = gScreen->glPaintOutput (attrib, transform, region, output, mask);
+
+ return status;
+}
+
+void
+PutScreen::donePaint ()
+{
+ PUT_SCREEN (screen);
+
+ if (ps->moreAdjust && ps->grabIndex)
+ cScreen->damageScreen (); // FIXME
+ else
+ {
+ if (ps->grabIndex)
+ {
+ /* release the screen grab */
+ screen->removeGrab (ps->grabIndex, NULL);
+ ps->grabIndex = 0;
+ }
+ }
+
+ cScreen->donePaint ();
+}
+
+/* This is our event handler. It directly hooks into the screen's X Event handler and allows us to handle
+ * our raw X Events
+ */
+
+void
+PutScreen::handleEvent (XEvent *event)
+{
+ switch (event->type)
+ {
+ /* handle client events */
+ case ClientMessage:
+ /* accept the custom atom for putting windows */
+ if (event->xclient.message_type == compizPutWindowAtom)
+ {
+ CompWindow *w;
+
+ w = screen->findWindow(event->xclient.window);
+ if (w)
+ {
+ /*
+ * get the values from the xclientmessage event and populate
+ * the options for put initiate
+ *
+ * the format is 32
+ * and the data is
+ * l[0] = x position - unused (for future PutExact)
+ * l[1] = y position - unused (for future PutExact)
+ * l[2] = viewport number
+ * l[3] = put type, int value from enum
+ * l[4] = output number
+ */
+ CompOption::Vector opt;
+ opt.reserve (5);
+
+ CompOption::Value value0 = (int) event->xclient.window;
+ opt.push_back (CompOption ( "window",CompOption::TypeInt));
+ opt[0].set (value0);
+
+ CompOption::Value value1 = (int) event->xclient.data.l[0];
+
+ opt.push_back (CompOption ( "x",CompOption::TypeInt));
+ opt[1].set (value1);
+
+ CompOption::Value value2 = (int) event->xclient.data.l[1];
+ opt.push_back (CompOption ( "y",CompOption::TypeInt));
+ opt[2].set (value2);
+
+ CompOption::Value value3 = (int) event->xclient.data.l[2];
+ opt.push_back (CompOption ( "viewport",CompOption::TypeInt));
+ opt[3].set (value3);
+
+ CompOption::Value value4 = (int) event->xclient.data.l[4];
+ opt.push_back (CompOption ( "output",CompOption::TypeInt));
+ opt[4].set (value4);
+
+ initiateCommon (NULL, 0, opt,
+ (PutType) event->xclient.data.l[3]);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ screen->handleEvent (event);
+}
+
+/* This gets called whenever the window needs to be repainted. WindowPaintAttrib gives you some
+ * attributes like brightness/saturation etc to play around with. GLMatrix is the window's
+ * transformation matrix. the unsigned int is the mask, have a look at opengl.h on what you can do
+ * with it */
+bool
+PutWindow::glPaint (const GLWindowPaintAttrib &attrib,
+ const GLMatrix &transform,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ bool status;
+ GLMatrix wTransform = transform;
+
+ PUT_WINDOW (window);
+
+ if (pw->adjust)
+ {
+
+ wTransform.translate ( pw->tx, pw->ty, 0.0f);
+
+ mask |= PAINT_WINDOW_TRANSFORMED_MASK;
+
+ }
+
+ status = gWindow->glPaint (attrib, wTransform, region, mask);
+
+ return status;
+}
+
+
+/*
+ * initiate action callback
+ */
+bool
+PutScreen::initiateCommon (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &option,
+ PutType type)
+{
+ CompWindow *w;
+ Window xid;
+
+ xid = CompOption::getIntOptionNamed (option, "window", 0);
+ if (!xid)
+ xid = screen->activeWindow ();
+
+ w = screen->findWindow (xid);
+ if (w)
+ {
+ CompScreen *s = screen;
+ int dx, dy;
+
+ PUT_SCREEN (s);
+
+ /* we don't want to do anything with override redirect windows */
+ if (w->overrideRedirect ())
+ return false;
+
+ /* we don't want to be moving the desktop and docks */
+ if (w->type () & (CompWindowTypeDesktopMask |
+ CompWindowTypeDockMask))
+ return false;
+
+ /* don't move windows without move action */
+ if (!(w->actions () & CompWindowActionMoveMask))
+ return false;
+
+ /* only allow movement of fullscreen windows to next output */
+ if (type != PutNextOutput &&
+ (w->type () & CompWindowTypeFullscreenMask))
+ {
+ return false;
+ }
+
+ /*
+ * handle the put types
+ */
+ if (!getDistance (w, type, option, &dx, &dy))
+ return false;
+
+ /* don't do anything if there is nothing to do */
+ if (!dx && !dy)
+ return true;
+
+ if (!ps->grabIndex)
+ {
+ /* this will keep put from working while something
+ else has a screen grab */
+ if (s->otherGrabExist ("put", 0))
+ return false;
+
+ /* we are ok, so grab the screen */
+ ps->grabIndex = s->pushGrab (s->invisibleCursor (), "put");
+ }
+
+ if (ps->grabIndex)
+ {
+ PUT_WINDOW (w);
+
+ ps->lastWindow = w->id ();
+
+ /* save the windows position in the saveMask
+ * this is used when unmaximizing the window
+ */
+ if (w->saveMask () & CWX)
+ w->saveWc ().x += dx;
+
+ if (w->saveMask () & CWY)
+ w->saveWc ().y += dy;
+
+ /* Make sure everyting starts out at the windows
+ current position */
+ pw->lastX = w->x () + pw->tx;
+ pw->lastY = w->y () + pw->ty;
+
+ pw->targetX = pw->lastX + dx;
+ pw->targetY = pw->lastY + dy;
+
+ /* mark for animation */
+ pw->adjust = true;
+ ps->moreAdjust = true;
+
+ /* cause repainting */
+ pw->cWindow->addDamage ();
+ }
+ }
+
+ /* tell event.c handleEvent to not call XAllowEvents */
+ return false;
+}
+
+PutType
+PutScreen::typeFromString (const CompString &type)
+{
+ if (type.compare("absolute") == 0)
+ return PutAbsolute;
+ else if (type.compare( "relative") == 0)
+ return PutRelative;
+ else if (type.compare( "pointer") == 0)
+ return PutPointer;
+ else if (type.compare( "viewport") == 0)
+ return (PutType) PutViewport;
+ else if (type.compare( "viewportleft") == 0)
+ return PutViewportLeft;
+ else if (type.compare( "viewportright") == 0)
+ return PutViewportRight;
+ else if (type.compare( "viewportup") == 0)
+ return PutViewportUp;
+ else if (type.compare( "viewportdown") == 0)
+ return PutViewportDown;
+ else if (type.compare( "nextoutput") == 0)
+ return PutNextOutput;
+ else if (type.compare( "restore") == 0)
+ return PutRestore;
+ else if (type.compare( "bottomleft") == 0)
+ return PutBottomLeft;
+ else if (type.compare( "emptybottomleft") == 0)
+ return PutEmptyBottomLeft;
+ else if (type.compare( "left") == 0)
+ return PutLeft;
+ else if (type.compare( "emptyleft") == 0)
+ return PutEmptyLeft;
+ else if (type.compare( "topleft") == 0)
+ return PutTopLeft;
+ else if (type.compare( "emptytopleft") == 0)
+ return PutEmptyTopLeft;
+ else if (type.compare( "top") == 0)
+ return PutTop;
+ else if (type.compare( "emptytop") == 0)
+ return PutEmptyTop;
+ else if (type.compare( "topright") == 0)
+ return PutTopRight;
+ else if (type.compare( "emptytopright") == 0)
+ return PutEmptyTopRight;
+ else if (type.compare( "right") == 0)
+ return PutRight;
+ else if (type.compare( "emptyright") == 0)
+ return PutEmptyRight;
+ else if (type.compare( "bottomright") == 0)
+ return PutBottomRight;
+ else if (type.compare( "emptybottomright") == 0)
+ return PutEmptyBottomRight;
+ else if (type.compare( "bottom") == 0)
+ return PutBottom;
+ else if (type.compare( "emptybottom") == 0)
+ return PutEmptyBottom;
+ else if (type.compare( "center") == 0)
+ return PutCenter;
+ else if (type.compare( "emptycenter") == 0)
+ return PutEmptyCenter;
+ else
+ return PutUnknown;
+}
+
+
+bool
+PutScreen::initiate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &option)
+{
+ PutType type = PutUnknown;
+ CompString typeString;
+
+ typeString = CompOption::getStringOptionNamed (option, "type", 0);
+ if (!typeString.empty())
+ type = typeFromString (typeString);
+
+/* if (type == (PutType) PutViewport)
+ return toViewport (action, state, option);
+ else*/
+ return initiateCommon (action, state, option,type);
+}
+
+
+PutScreen::PutScreen (CompScreen *screen) :
+ PrivateHandler <PutScreen, CompScreen> (screen),
+ PutOptions (putVTable->getMetadata ()),
+ screen (screen),
+ cScreen (CompositeScreen::get (screen)),
+ gScreen (GLScreen::get (screen)),
+ lastWindow (None),
+ lastType (PutUnknown),
+ moreAdjust (false),
+ grabIndex (0)
+{
+ ScreenInterface::setHandler (screen);
+ CompositeScreenInterface::setHandler (cScreen);
+ GLScreenInterface::setHandler (gScreen);
+
+ compizPutWindowAtom = XInternAtom(screen->dpy (),
+ "_COMPIZ_PUT_WINDOW", 0);
+
+#define setAction(action, type) \
+ optionSet##action##Initiate (boost::bind (&PutScreen::initiateCommon, \
+ this, _1,_2,_3,type))
+
+ /* Keys */
+ setAction(PutCenterKey,PutCenter);
+ setAction(PutEmptyCenterKey,PutEmptyCenter);
+ setAction(PutLeftKey,PutLeft);
+ setAction(PutEmptyLeftKey,PutEmptyLeft);
+ setAction(PutRightKey,PutRight);
+ setAction(PutEmptyRightKey,PutEmptyRight);
+ setAction(PutTopKey,PutTop);
+ setAction(PutEmptyTopKey,PutEmptyTop);
+ setAction(PutBottomKey,PutBottom);
+ setAction(PutEmptyBottomKey,PutEmptyBottom);
+ setAction(PutTopleftKey,PutTopLeft);
+ setAction(PutEmptyTopleftKey,PutEmptyTopLeft);
+ setAction(PutToprightKey,PutTopRight);
+ setAction(PutEmptyToprightKey,PutEmptyTopRight);
+ setAction(PutBottomleftKey,PutBottomLeft);
+ setAction(PutEmptyBottomleftKey,PutEmptyBottomLeft);
+ setAction(PutBottomrightKey,PutBottomRight);
+ setAction(PutEmptyBottomrightKey,PutEmptyBottomRight);
+
+ /* Buttons */
+
+ setAction(PutCenterButton,PutCenter);
+ setAction(PutEmptyCenterButton,PutEmptyCenter);
+ setAction(PutLeftButton,PutLeft);
+ setAction(PutEmptyLeftButton,PutEmptyLeft);
+ setAction(PutRightButton,PutRight);
+ setAction(PutEmptyRightButton,PutEmptyRight);
+ setAction(PutTopButton,PutTop);
+ setAction(PutEmptyTopButton,PutEmptyTop);
+ setAction(PutBottomButton,PutBottom);
+ setAction(PutEmptyBottomButton,PutEmptyBottom);
+ setAction(PutTopleftButton,PutTopLeft);
+ setAction(PutEmptyTopleftButton,PutEmptyTopLeft);
+ setAction(PutToprightButton,PutTopRight);
+ setAction(PutEmptyToprightButton,PutEmptyTopRight);
+ setAction(PutBottomleftButton,PutBottomLeft);
+ setAction(PutEmptyBottomleftButton,PutEmptyBottomLeft);
+ setAction(PutBottomrightButton,PutBottomRight);
+ setAction(PutEmptyBottomrightButton,PutEmptyBottomRight);
+}
+
+PutScreen::~PutScreen () { }
+
+PutWindow::PutWindow (CompWindow *window) :
+ PrivateHandler <PutWindow, CompWindow> (window),
+ window (window),
+ cWindow (CompositeWindow::get (window)),
+ gWindow (GLWindow::get (window)),
+ xVelocity (0),
+ yVelocity (0),
+ tx (0),
+ ty (0),
+ lastX (window->serverX ()),
+ lastY (window->serverY ()),
+ adjust (false)
+{
+ WindowInterface::setHandler (window); // Sets the window function hook handler
+ CompositeWindowInterface::setHandler (cWindow); // Ditto for cWindow
+ GLWindowInterface::setHandler (gWindow); // Ditto for gWindow
+}
+
+PutWindow::~PutWindow () { }
+
+bool
+PutPluginVTable::init ()
+{
+ std::cout << "Plugin loaded" << std::endl;
+ if (!CompPlugin::checkPluginABI ("core", CORE_ABIVERSION))
+ return false;
+ if (!CompPlugin::checkPluginABI ("composite", COMPIZ_COMPOSITE_ABI))
+ return false;
+ if (!CompPlugin::checkPluginABI ("opengl", COMPIZ_OPENGL_ABI))
+ return false;
+ return true;
+}
diff --git a/put.h b/put.h
new file mode 100644
index 0000000..e3d130e
--- /dev/null
+++ b/put.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2006 Darryll Truchan <moppsy@comcast.net>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * TODO:
+ * Region -> CompRegion
+ * XRectangle -> CompRect
+ */
+
+
+#include <core/core.h>
+#include <core/privatehandler.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+#include "put_options.h"
+
+enum PutType
+{
+ PutUnknown = 0,
+ PutBottomLeft = 1,
+ PutBottom = 2,
+ PutBottomRight = 3,
+ PutLeft = 4,
+ PutCenter = 5,
+ PutRight = 6,
+ PutTopLeft = 7,
+ PutTop = 8,
+ PutTopRight = 9,
+ PutRestore = 10,
+ PutViewport = 11,
+ PutViewportLeft = 12,
+ PutViewportRight = 13,
+ PutAbsolute = 14,
+ PutPointer = 15,
+ PutViewportUp = 16,
+ PutViewportDown = 17,
+ PutRelative = 18,
+ PutNextOutput = 19,
+ PutEmptyBottomLeft = 20,
+ PutEmptyBottom = 21,
+ PutEmptyBottomRight = 22,
+ PutEmptyLeft = 23,
+ PutEmptyCenter = 24,
+ PutEmptyRight = 25,
+ PutEmptyTopLeft = 26,
+ PutEmptyTop = 27,
+ PutEmptyTopRight,
+};
+
+class PutScreen :
+ public PrivateHandler <PutScreen, CompScreen>,
+ public PutOptions,
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface
+{
+
+ public:
+
+ PutScreen (CompScreen *s);
+ ~PutScreen ();
+
+
+ void
+ preparePaint (int);
+
+ bool
+ glPaintOutput (const GLScreenPaintAttrib &,
+ const GLMatrix &, const CompRegion &,
+ CompOutput *, unsigned int);
+
+ void
+ donePaint ();
+
+ void
+ handleEvent (XEvent *);
+
+ bool
+ initiateCommon (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options,
+ PutType type);
+
+ bool
+ initiate (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &option);
+ private:
+
+ Region
+ emptyRegion (CompWindow *window,
+ Region region);
+ bool
+ boxCompare (BOX a,
+ BOX b);
+
+ BOX
+ extendBox (CompWindow *w,
+ BOX tmp,
+ Region r,
+ bool xFirst,
+ bool left,
+ bool right,
+ bool up,
+ bool down);
+ BOX
+ findRect (CompWindow *w,
+ Region r,
+ bool left,
+ bool right,
+ bool up,
+ bool down);
+
+ unsigned int
+ computeResize(CompWindow *w,
+ XWindowChanges *xwc,
+ bool left,
+ bool right,
+ bool up,
+ bool down);
+
+ int
+ adjustVelocity (CompWindow *w);
+
+ void
+ finishWindowMovement (CompWindow *w);
+
+ bool
+ getDistance (CompWindow *w,
+ PutType type,
+ CompOption::Vector &option,
+ int *distX,
+ int *distY);
+
+ unsigned int
+ getOutputForWindow (CompWindow *w);
+
+ PutType
+ typeFromString (const CompString &);
+
+ /* Data */
+
+ CompScreen *screen;
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ Atom compizPutWindowAtom;
+ Window lastWindow;
+ PutType lastType;
+ int moreAdjust;
+ CompScreen::GrabHandle grabIndex;
+
+ friend class PutWindow;
+};
+class PutWindow :
+ public PrivateHandler <PutWindow, CompWindow>,
+ public WindowInterface,
+ public CompositeWindowInterface,
+ public GLWindowInterface
+{
+
+ public:
+
+ PutWindow (CompWindow *window);
+ ~PutWindow ();
+
+ CompWindow *window;
+ CompositeWindow *cWindow;
+ GLWindow *gWindow;
+
+ bool
+ glPaint (const GLWindowPaintAttrib &, const GLMatrix &,
+ const CompRegion &, unsigned int);
+
+ private:
+ GLfloat xVelocity, yVelocity; /* animation velocity */
+ GLfloat tx, ty; /* animation translation */
+
+ int lastX, lastY; /* starting position */
+ int targetX, targetY; /* target of the animation */
+
+ Bool adjust; /* animation flag */
+ friend class PutScreen;
+
+};
+
+#define PUT_SCREEN(s) \
+PutScreen *ps = PutScreen::get (s);
+
+#define PUT_WINDOW(w) \
+PutWindow *pw = PutWindow::get (w);
+
+class PutPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow<PutScreen, PutWindow>
+{
+ public:
+
+ bool init ();
+
+ /* This implements ::getOption and ::setOption in your screen class for you. Yay */
+
+ PLUGIN_OPTION_HELPER (PutScreen);
+};
+
+
+COMPIZ_PLUGIN_20081216 (put, PutPluginVTable);
+