summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Spilsbury <sam.spilsbury@canonical.com>2010-12-09 17:37:25 +0800
committerSam Spilsbury <sam.spilsbury@canonical.com>2010-12-09 17:37:25 +0800
commita4e52b0935baa403bec3c2b18e6ec2903c48ff3a (patch)
treebd87e1d63f42ca5004bf52753917f5db772d728c
parent4666435ec53105675c67225e6d5fd18101627353 (diff)
downloadcompiz-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
-rw-r--r--plugins/resize/src/resize.cpp149
-rw-r--r--plugins/resize/src/resize.h2
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 :