diff options
author | Sam Spilsbury <sam.spilsbury@canonical.com> | 2010-12-09 17:37:25 +0800 |
---|---|---|
committer | Sam Spilsbury <sam.spilsbury@canonical.com> | 2010-12-09 17:37:25 +0800 |
commit | a4e52b0935baa403bec3c2b18e6ec2903c48ff3a (patch) | |
tree | bd87e1d63f42ca5004bf52753917f5db772d728c /plugins | |
parent | 4666435ec53105675c67225e6d5fd18101627353 (diff) | |
download | compiz-with-glib-mainloop-a4e52b0935baa403bec3c2b18e6ec2903c48ff3a.tar.gz compiz-with-glib-mainloop-a4e52b0935baa403bec3c2b18e6ec2903c48ff3a.tar.bz2 |
Be a little bit more clever about constraining resizes to workareas.
Basically we want to constrain resizes to workareas, but not
in the case where two outputs touch. In the case that two outputs touch
they must be directly adjacent and there must not be a panel or dock in
the way
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/resize/src/resize.cpp | 149 | ||||
-rw-r--r-- | plugins/resize/src/resize.h | 2 |
2 files changed, 147 insertions, 4 deletions
diff --git a/plugins/resize/src/resize.cpp b/plugins/resize/src/resize.cpp index a8d3c4f..8cab482 100644 --- a/plugins/resize/src/resize.cpp +++ b/plugins/resize/src/resize.cpp @@ -183,6 +183,122 @@ ResizeScreen::finishResizing () w = NULL; } +#define TOUCH_LEFT 1 +#define TOUCH_RIGHT 2 +#define TOUCH_TOP 3 +#define TOUCH_BOTTOM 4 + +static unsigned int +findTouchingOutput (int touchPoint, unsigned int side) +{ + for (unsigned int i = 0; i < screen->outputDevs ().size (); i++) + { + CompOutput &o = screen->outputDevs ().at (i); + if (side == TOUCH_LEFT) + { + if (o.left () == touchPoint) + return i; + } + if (side == TOUCH_RIGHT) + { + if (o.right () == touchPoint) + return i; + } + if (side == TOUCH_TOP) + { + if (o.top () == touchPoint) + return i; + } + if (side == TOUCH_BOTTOM) + { + if (o.bottom () == touchPoint) + return i; + } + } + + return -1; +} + +static void +getPointForTp (unsigned int tp, unsigned int output, int &op, int &wap) +{ + CompRect og = CompRect (screen->outputDevs ().at (output)); + CompRect wag = screen->outputDevs ().at (output).workArea (); + + switch (tp) + { + case TOUCH_LEFT: + op = og.right (); + wap = wag.right (); + break; + case TOUCH_RIGHT: + op = og.left (); + wap = wag.left (); + break; + case TOUCH_TOP: + op = og.bottom (); + wap = wag.bottom (); + break; + case TOUCH_BOTTOM: + op = og.top (); + wap = wag.top (); + break; + default: + return; + } +} + +/* Be a little bit intelligent about how we calculate + * the workarea. Basically we want to be enclosed in + * any area that is obstructed by panels, but not + * where two outputs meet + * + * Also, it does not make sense to resize over + * non-touching outputs, so detect that case too + * */ + +static int +getOutputForEdge (int windowOutput, unsigned int touch) +{ + int op, wap; + int ret = 0; + + getPointForTp (touch, windowOutput, op, wap); + + if (op == wap) + { + int co = windowOutput; + + do + { + int oco = co; + + getPointForTp (touch, co, op, wap); + + co = findTouchingOutput (op, touch); + + /* Could not find a leftmost output from here + * so we must have hit the edge of the universe */ + if (co == -1) + { + ret = oco; + co = -1; + break; + } + + /* There is something in the way here.... */ + if (op != wap) + { + ret = co; + co = -1; + } + } + while (co != -1); + } + + return ret; +} + static bool resizeInitiate (CompAction *action, CompAction::State state, @@ -356,12 +472,38 @@ resizeInitiate (CompAction *action, if (sourceExternalApp) { int output = w->outputDevice (); + int lco, tco, bco, rco; + + lco = tco = bco = rco = output; + /* Prevent resizing beyond work area edges when resize is initiated externally (e.g. with window frame or menu) and not with a key (e.g. alt+button) */ rs->offWorkAreaConstrained = true; - rs->grabWindowWorkArea = - &screen->outputDevs ().at (output).workArea (); + + tco = getOutputForEdge (output, TOUCH_BOTTOM); + bco = getOutputForEdge (output, TOUCH_TOP); + lco = getOutputForEdge (output, TOUCH_LEFT); + rco = getOutputForEdge (output, TOUCH_TOP); + + /* Now we need to form one big rect which describes + * the available workarea */ + + int left = screen->outputDevs ().at (lco).workArea ().left (); + int right = screen->outputDevs ().at (rco).workArea ().right (); + int top = screen->outputDevs ().at (tco).workArea ().top (); + int bottom = screen->outputDevs ().at (bco).workArea ().bottom (); + + if (rs->grabWindowWorkArea) + delete rs->grabWindowWorkArea; + + rs->grabWindowWorkArea = new CompRect (0, 0, 0, 0); + rs->grabWindowWorkArea->setLeft (left); + rs->grabWindowWorkArea->setRight (right); + rs->grabWindowWorkArea->setTop (top); + rs->grabWindowWorkArea->setBottom (bottom); + + rs->inRegionStatus = false; rs->lastGoodHotSpotY = -1; rs->lastGoodSize = w->serverSize (); @@ -1523,7 +1665,8 @@ ResizeScreen::ResizeScreen (CompScreen *s) : centeredMask (0), releaseButton (0), isConstrained (false), - offWorkAreaConstrained (true) + offWorkAreaConstrained (true), + grabWindowWorkArea (NULL) { CompOption::Vector atomTemplate; Display *dpy = s->dpy (); diff --git a/plugins/resize/src/resize.h b/plugins/resize/src/resize.h index afab4d8..59e0c71 100644 --- a/plugins/resize/src/resize.h +++ b/plugins/resize/src/resize.h @@ -148,7 +148,7 @@ class ResizeScreen : CompSize lastGoodSize; bool offWorkAreaConstrained; - const CompRect *grabWindowWorkArea; + CompRect *grabWindowWorkArea; }; class ResizeWindow : |