summaryrefslogtreecommitdiff
path: root/plugins/unity-mt-grab-handles/src
diff options
authorNeil Jagdish Patel <neil.patel@canonical.com>2011-06-20 21:46:03 +0100
committerNeil Jagdish Patel <neil.patel@canonical.com>2011-06-20 21:46:03 +0100
commitcf288adbce32bd5e2ffa2a55a738787a1cf6c3e7 (patch)
treefdf47e0dd679f005e70db657d855c31faa3f5290 /plugins/unity-mt-grab-handles/src
parent04f0462680d375d60c35435e2e1042997b78f246 (diff)
Initial go at making things sane again
(bzr r1242.2.1)
Diffstat (limited to 'plugins/unity-mt-grab-handles/src')
-rw-r--r--plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp931
-rw-r--r--plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h222
2 files changed, 1153 insertions, 0 deletions
diff --git a/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp
new file mode 100644
index 000000000..109cfee86
--- /dev/null
+++ b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.cpp
@@ -0,0 +1,931 @@
+/*
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
+ */
+
+#include "unity-mt-grab-handles.h"
+#include <iostream>
+
+#define NUM_HANDLES 9
+#define FADE_MSEC UnityMTGrabHandlesScreen::get (screen)->optionGetFadeDuration ()
+
+COMPIZ_PLUGIN_20090315 (unitymtgrabhandles, UnityMTGrabHandlesPluginVTable);
+
+void
+Unity::MT::GrabHandle::reposition (CompPoint *p, bool hard)
+{
+ XWindowChanges xwc;
+ unsigned int vm = 0;
+
+ UMTGH_SCREEN (screen);
+
+ us->cScreen->damageRegion ((CompRect &) *this);
+
+ if (p)
+ {
+ setX (p->x ());
+ setY (p->y ());
+
+ xwc.x = x ();
+ xwc.y = y ();
+
+ vm |= (CWX | CWY);
+ }
+
+ vm |= (CWStackMode | CWSibling);
+
+ xwc.stack_mode = Above;
+ xwc.sibling = mOwner;
+
+ if (hard)
+ {
+ XConfigureWindow (screen->dpy (), mIpw, vm, &xwc);
+ XSelectInput (screen->dpy (), mIpw, ButtonPressMask | ButtonReleaseMask);
+ }
+
+ us->cScreen->damageRegion ((CompRect &) *this);
+}
+
+void
+Unity::MT::GrabHandle::hide ()
+{
+ if (mIpw)
+ XUnmapWindow (screen->dpy (), mIpw);
+}
+
+void
+Unity::MT::GrabHandle::show ()
+{
+ if (!mIpw)
+ {
+ XSetWindowAttributes xswa;
+
+ xswa.override_redirect = TRUE;
+
+ mIpw = XCreateWindow (screen->dpy (),
+ screen->root (),
+ -100, -100,
+ mTexture->second.width (),
+ mTexture->second.height (),
+ 0,
+ CopyFromParent, InputOnly,
+ CopyFromParent, CWOverrideRedirect, &xswa);
+
+ UnityMTGrabHandlesScreen::get (screen)->addHandleWindow (this, mIpw);
+
+ reposition (NULL, true);
+ }
+
+ XMapWindow (screen->dpy (), mIpw);
+}
+
+Unity::MT::TextureLayout
+Unity::MT::GrabHandle::layout ()
+{
+ return TextureLayout (&mTexture->first, (CompRect *) this);
+}
+
+Unity::MT::GrabHandle::GrabHandle (TextureSize *t, Window owner, unsigned int id) :
+ mIpw (0),
+ mOwner (owner),
+ mTexture (t),
+ mId (id)
+{
+ setX (0);
+ setY (0);
+ setSize (t->second);
+}
+
+Unity::MT::GrabHandle::~GrabHandle ()
+{
+ if (mIpw)
+ {
+ UnityMTGrabHandlesScreen::get (screen)->removeHandleWindow (mIpw);
+
+ XDestroyWindow (screen->dpy (), mIpw);
+ }
+}
+
+void
+Unity::MT::GrabHandle::handleButtonPress (XButtonEvent *be)
+{
+ /* Send _NET_MOVERESIZE to root window so that a button-1
+ * press on this window will start resizing the window around */
+ XEvent event;
+ CompWindow *w;
+ w = screen->findTopLevelWindow (mOwner, false);
+
+ if (!w)
+ return;
+
+ if (screen->getOption ("raise_on_click"))
+ w->updateAttributes (CompStackingUpdateModeAboveFullscreen);
+
+ if (w->id () != screen->activeWindow ())
+ if (w->focus ())
+ w->moveInputFocusTo ();
+
+ event.xclient.type = ClientMessage;
+ event.xclient.display = screen->dpy ();
+
+ event.xclient.serial = 0;
+ event.xclient.send_event = true;
+
+ /* FIXME: Need to call findWindow since we need to send the
+ * _NET_WM_MOVERESIZE request to the client not the frame
+ * which we are tracking. That's a bit shitty */
+ event.xclient.window = w->id ();
+ event.xclient.message_type = Atoms::wmMoveResize;
+ event.xclient.format = 32;
+
+ event.xclient.data.l[0] = be->x_root;
+ event.xclient.data.l[1] = be->y_root;
+ event.xclient.data.l[2] = mId;
+ event.xclient.data.l[3] = be->button;
+ event.xclient.data.l[4] = 1;
+
+ XSendEvent (screen->dpy (), screen->root (), false,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ &event);
+}
+
+void
+Unity::MT::GrabHandleGroup::show ()
+{
+ foreach (Unity::MT::GrabHandle &handle, *this)
+ handle.show ();
+
+ mState = FADE_IN;
+}
+
+void
+Unity::MT::GrabHandleGroup::hide ()
+{
+ foreach (Unity::MT::GrabHandle &handle, *this)
+ handle.hide ();
+
+ mState = FADE_OUT;
+}
+
+bool
+Unity::MT::GrabHandleGroup::animate (unsigned int msec)
+{
+ mMoreAnimate = false;
+
+ switch (mState)
+ {
+ case FADE_IN:
+
+ mOpacity += ((float) msec / (float) FADE_MSEC) * OPAQUE;
+
+ if (mOpacity >= OPAQUE)
+ {
+ mOpacity = OPAQUE;
+ mState = NONE;
+ }
+ break;
+ case FADE_OUT:
+ mOpacity -= ((float) msec / (float) FADE_MSEC) * OPAQUE;
+
+ if (mOpacity <= 0)
+ {
+ mOpacity = 0;
+ mState = NONE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ mMoreAnimate = mState != NONE;
+
+ return mMoreAnimate;
+}
+
+int
+Unity::MT::GrabHandleGroup::opacity ()
+{
+ return mOpacity;
+}
+
+bool
+Unity::MT::GrabHandleGroup::visible ()
+{
+ return mOpacity > 0.0f;
+}
+
+bool
+Unity::MT::GrabHandleGroup::needsAnimate ()
+{
+ return mMoreAnimate;
+}
+
+void
+Unity::MT::GrabHandleGroup::relayout (const CompRect &rect, bool hard)
+{
+ /* Each grab handle at each vertex, eg:
+ *
+ * 1 - topleft
+ * 2 - top
+ * 3 - topright
+ * 4 - right
+ * 5 - bottom-right
+ * 6 - bottom
+ * 7 - bottom-left
+ * 8 - left
+ */
+
+ const float pos[9][2] = {
+ {0.0f, 0.0f}, {0.5f, 0.0f}, {1.0f, 0.0f},
+ {1.0f, 0.5f}, {1.0f, 1.0f},
+ {0.5f, 1.0f}, {0.0f, 1.0f}, {0.0f, 0.5f},
+ {0.5f, 0.5f} /* middle */
+ };
+
+ for (unsigned int i = 0; i < NUM_HANDLES; i++)
+ {
+ Unity::MT::GrabHandle &handle = at (i);
+ CompPoint p (rect.x () + rect.width () * pos[i][0] -
+ handle.width () / 2,
+ rect.y () + rect.height () * pos[i][1] -
+ handle.height () / 2);
+
+ handle.reposition (&p, hard);
+ }
+}
+
+Unity::MT::GrabHandleGroup::GrabHandleGroup (Window owner) :
+ mState (NONE),
+ mOpacity (0.0f),
+ mMoreAnimate (false)
+{
+ UMTGH_SCREEN (screen);
+
+ for (unsigned int i = 0; i < NUM_HANDLES; i++)
+ push_back (Unity::MT::GrabHandle (&us->textures ().at (i), owner, i));
+}
+
+Unity::MT::GrabHandleGroup::~GrabHandleGroup ()
+{
+ UMTGH_SCREEN (screen);
+
+ foreach (Unity::MT::GrabHandle &handle, *this)
+ us->cScreen->damageRegion ((CompRect &) handle);
+}
+
+std::vector <Unity::MT::TextureLayout>
+Unity::MT::GrabHandleGroup::layout ()
+{
+ std::vector <Unity::MT::TextureLayout> layout;
+
+ foreach (Unity::MT::GrabHandle &handle, *this)
+ layout.push_back (handle.layout ());
+
+ return layout;
+}
+
+/* Super speed hack */
+static bool
+sortPointers (const CompWindow *p1, const CompWindow *p2)
+{
+ return (void *) p1 < (void *) p2;
+}
+
+void
+UnityMTGrabHandlesScreen::handleEvent (XEvent *event)
+{
+ Unity::MT::GrabHandle *handle;
+ std::map <Window, Unity::MT::GrabHandle *>::iterator it;
+ CompWindow *w, *oldPrev, *oldNext;
+
+ w = oldPrev = oldNext = NULL;
+
+ switch (event->type)
+ {
+ case FocusIn:
+ case FocusOut:
+ if (event->xfocus.mode == NotifyUngrab)
+ {
+ foreach (CompWindow *w, screen->windows ())
+ {
+ UnityMTGrabHandlesWindow *mtwindow = UnityMTGrabHandlesWindow::get (w);
+ if (mtwindow->handleTimerActive ())
+ mtwindow->resetTimer ();
+ }
+ }
+ break;
+ case ClientMessage:
+
+ if (event->xclient.message_type == mCompResizeWindowAtom)
+ {
+ CompWindow *w = screen->findWindow (event->xclient.window);
+
+ if (w)
+ {
+ CompRect r;
+ UMTGH_WINDOW (w);
+
+ r.setGeometry (event->xclient.data.l[0] - w->input ().left,
+ event->xclient.data.l[1] - w->input ().top,
+ event->xclient.data.l[2] + w->input ().left + w->input ().right,
+ event->xclient.data.l[3] + w->input ().top + w->input ().bottom);
+
+ uw->relayout (r, false);
+ }
+ }
+
+ break;
+
+ case PropertyNotify:
+
+ /* Stacking order of managed clients changed, check old
+ * stacking order and ensure stacking of handles
+ * that were changed in the stack */
+
+
+ if (event->xproperty.atom == Atoms::clientListStacking)
+ {
+ CompWindowVector invalidated (0);
+ CompWindowVector clients = screen->clientList (true);
+ CompWindowVector oldClients = mLastClientListStacking;
+ CompWindowVector clientListStacking = screen->clientList (true);
+ /* Windows can be removed and added from the client list
+ * here at the same time (eg hide/unhide launcher ... racy)
+ * so we need to check if the client list contains the same
+ * windows as it used to. Sort both lists and compare ... */
+
+ std::sort (clients.begin (), clients.end (), sortPointers);
+ std::sort (oldClients.begin (),
+ oldClients.end (), sortPointers);
+
+ if (clients != mLastClientListStacking)
+ invalidated = clients;
+ else
+ {
+ CompWindowVector::const_iterator cit = clientListStacking.begin ();
+ CompWindowVector::const_iterator oit = mLastClientListStacking.begin ();
+
+ for (; cit != clientListStacking.end (); cit++, oit++)
+ {
+ /* All clients from this point onwards in cit are invalidated
+ * so splice the list to the end of the new client list
+ * and update the stacking of handles there */
+ if ((*cit)->id () != (*oit)->id ())
+ {
+ invalidated.push_back ((*cit));
+ }
+ }
+ }
+
+ foreach (CompWindow *w, invalidated)
+ UnityMTGrabHandlesWindow::get (w)->restackHandles ();
+
+ mLastClientListStacking = clients;
+ }
+
+ break;
+
+ case ButtonPress:
+
+ if (event->xbutton.button != 1)
+ break;
+
+ it = mInputHandles.find (event->xbutton.window);
+
+ if (it != mInputHandles.end ())
+ {
+ handle = it->second;
+ if (handle)
+ handle->handleButtonPress ((XButtonEvent *) event);
+ }
+
+ break;
+ case ConfigureNotify:
+
+ w = screen->findTopLevelWindow (event->xconfigure.window);
+
+ if (w)
+ UnityMTGrabHandlesWindow::get (w)->relayout (w->inputRect (), true);
+
+ break;
+
+ case MapNotify:
+
+ it = mInputHandles.find (event->xmap.window);
+
+ if (it != mInputHandles.end ())
+ {
+ if (it->second)
+ it->second->reposition (NULL, true);
+ }
+
+ break;
+ default:
+
+ break;
+ }
+
+ screen->handleEvent (event);
+}
+
+void
+UnityMTGrabHandlesScreen::donePaint ()
+{
+ if (mMoreAnimate)
+ {
+ foreach (Unity::MT::GrabHandleGroup *handles, mGrabHandles)
+ {
+ if (handles->needsAnimate ())
+ {
+ foreach (Unity::MT::GrabHandle &handle, *handles)
+ cScreen->damageRegion ((CompRect &) handle);
+ }
+ }
+ }
+
+ cScreen->donePaint ();
+}
+
+void
+UnityMTGrabHandlesScreen::preparePaint (int msec)
+{
+ if (mMoreAnimate)
+ {
+ mMoreAnimate = false;
+
+ foreach (Unity::MT::GrabHandleGroup *handles, mGrabHandles)
+ {
+ mMoreAnimate |= handles->animate (msec);
+ }
+ }
+
+ cScreen->preparePaint (msec);
+}
+
+bool
+UnityMTGrabHandlesWindow::handleTimerActive ()
+{
+ return _timer_handle != 0;
+}
+
+bool
+UnityMTGrabHandlesWindow::allowHandles ()
+{
+ /* Not on windows we can't move or resize */
+ if (!(window->actions () & CompWindowActionResizeMask))
+ return false;
+
+ if (!(window->actions () & CompWindowActionMoveMask))
+ return false;
+
+ /* Not on override redirect windows */
+ if (window->overrideRedirect ())
+ return false;
+
+ return true;
+}
+
+void
+UnityMTGrabHandlesWindow::getOutputExtents (CompWindowExtents &output)
+{
+ if (mHandles)
+ {
+ /* Only care about the handle on the outside */
+ output.left = MAX (output.left, window->borderRect ().left () + mHandles->at (0).width () / 2);
+ output.right = MAX (output.right, window->borderRect ().right () + mHandles->at (0).width () / 2);
+ output.top = MAX (output.top, window->borderRect ().top () + mHandles->at (0).height () / 2);
+ output.bottom = MAX (output.bottom, window->borderRect ().bottom () + mHandles->at (0).height () / 2);
+ }
+ else
+ window->getOutputExtents (output);
+
+}
+
+bool
+UnityMTGrabHandlesWindow::glDraw (const GLMatrix &transform,
+ GLFragment::Attrib &fragment,
+ const CompRegion &region,
+ unsigned int mask)
+{
+ /* Draw the window on the bottom, we will be drawing the
+ * handles on top */
+ bool status = gWindow->glDraw (transform, fragment, region, mask);
+
+ UMTGH_SCREEN (screen);
+
+ if (mHandles && mHandles->visible ())
+ {
+ unsigned int handle = 0;
+
+ foreach (Unity::MT::TextureLayout layout, mHandles->layout ())
+ {
+ /* We want to set the geometry of the dim to the window
+ * region */
+ CompRegion reg = CompRegion (*layout.second);
+
+ struct _skipInfo
+ {
+ unsigned int vstate;
+ unsigned int hstate;
+ unsigned int handles[9];
+ };
+
+ const struct _skipInfo skip[3] = {
+ {CompWindowStateMaximizedVertMask,
+ CompWindowStateMaximizedVertMask,
+ { 1, 1, 1, 0, 1, 1, 1, 0, 0 }},
+ {CompWindowStateMaximizedHorzMask,
+ CompWindowStateMaximizedHorzMask,
+ {1, 0, 1, 1, 1, 0, 1, 1, 0 }},
+ {CompWindowStateMaximizedVertMask,
+ CompWindowStateMaximizedHorzMask,
+ {1, 1, 1, 1, 1, 1, 1, 1, 1 }}};
+
+ foreach (GLTexture *tex, *layout.first)
+ {
+ GLTexture::MatrixList matl;
+ GLTexture::Matrix mat = tex->matrix ();
+ CompRegion paintRegion (region);
+ bool skipHandle = false;
+
+ for (unsigned int j = 0; j < 3; j++)
+ {
+ if (skip[j].vstate & window->state () &&
+ skip[j].hstate & window->state ())
+ {
+ if (skip[j].handles[handle])
+ {
+ skipHandle = true;
+ break;
+ }
+ }
+ }
+
+ if (skipHandle)
+ break;
+
+ /* We can reset the window geometry since it will be
+ * re-added later */
+ gWindow->geometry ().reset ();
+
+ /* Scale the handles */
+ mat.xx *= 1;
+ mat.yy *= 1;
+
+ /* Not sure what this does, but it is necessary
+ * (adjusts for scale?) */
+ mat.x0 -= mat.xx * reg.boundingRect ().x1 ();
+ mat.y0 -= mat.yy * reg.boundingRect ().y1 ();
+
+ matl.push_back (mat);
+
+ if (mask & PAINT_WINDOW_TRANSFORMED_MASK)
+ paintRegion = infiniteRegion;
+
+ /* Now allow plugins to mess with the geometry of our
+ * dim (so we get a nice render for things like
+ * wobbly etc etc */
+ gWindow->glAddGeometry (matl, reg, paintRegion);
+
+ /* Did it succeed? */
+ if (gWindow->geometry ().vertices)
+ {
+ fragment.setOpacity (mHandles->opacity ());
+ /* Texture rendering set-up */
+ us->gScreen->setTexEnvMode (GL_MODULATE);
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ /* Draw the dim texture with all of it's modified
+ * geometry glory */
+ gWindow->glDrawTexture (tex, fragment, mask | PAINT_WINDOW_BLEND_MASK
+ | PAINT_WINDOW_TRANSLUCENT_MASK |
+ PAINT_WINDOW_TRANSFORMED_MASK);
+ /* Texture rendering tear-down */
+ glBlendFunc (GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ us->gScreen->setTexEnvMode (GL_REPLACE);
+ }
+ }
+
+ handle++;
+ }
+ }
+
+ return status;
+}
+
+void
+UnityMTGrabHandlesWindow::relayout (const CompRect &r, bool hard)
+{
+ if (mHandles)
+ mHandles->relayout (r, hard);
+}
+
+void
+UnityMTGrabHandlesWindow::grabNotify (int x, int y, unsigned int state, unsigned int mask)
+{
+ window->grabNotify (x, y, state, mask);
+}
+
+void
+UnityMTGrabHandlesWindow::moveNotify (int dx, int dy, bool immediate)
+{
+ if (mHandles)
+ mHandles->relayout ((const CompRect &) window->inputRect (), false);
+
+ window->moveNotify (dx, dy, immediate);
+}
+
+void
+UnityMTGrabHandlesWindow::ungrabNotify ()
+{
+ window->ungrabNotify ();
+}
+
+bool
+UnityMTGrabHandlesWindow::handlesVisible ()
+{
+ if (!mHandles)
+ return false;
+
+ return mHandles->visible ();
+}
+
+void
+UnityMTGrabHandlesWindow::hideHandles ()
+{
+ if (mHandles)
+ mHandles->hide ();
+
+ window->updateWindowOutputExtents ();
+ cWindow->damageOutputExtents ();
+
+ disableTimer ();
+}
+
+gboolean
+UnityMTGrabHandlesWindow::onHideTimeout (gpointer data)
+{
+ UnityMTGrabHandlesWindow *self = static_cast<UnityMTGrabHandlesWindow*> (data);
+
+ if (screen->grabbed ())
+ return true;
+
+ // hack
+ self->hideHandles ();
+ self->_mt_screen->mMoreAnimate = true;
+ self->_timer_handle = 0;
+ return false;
+}
+
+void
+UnityMTGrabHandlesWindow::resetTimer ()
+{
+ if (_timer_handle)
+ g_source_remove (_timer_handle);
+
+ _timer_handle = g_timeout_add (2000, &UnityMTGrabHandlesWindow::onHideTimeout, this);
+}
+
+void
+UnityMTGrabHandlesWindow::disableTimer ()
+{
+ if (_timer_handle)
+ g_source_remove (_timer_handle);
+}
+
+void
+UnityMTGrabHandlesWindow::showHandles (bool use_timer)
+{
+ if (!mHandles)
+ {
+ mHandles = new Unity::MT::GrabHandleGroup (window->frame ());
+ UnityMTGrabHandlesScreen::get (screen)->addHandles (mHandles);
+ }
+
+ if (!mHandles->visible ())
+ {
+ activate ();
+ mHandles->show ();
+ mHandles->relayout (window->inputRect (), true);
+
+ window->updateWindowOutputExtents ();
+ cWindow->damageOutputExtents ();
+ }
+
+ if (use_timer)
+ resetTimer ();
+ else
+ disableTimer ();
+}
+
+void
+UnityMTGrabHandlesWindow::restackHandles ()
+{
+ if (!mHandles)
+ return;
+
+ foreach (Unity::MT::GrabHandle &handle, *mHandles)
+ handle.reposition (NULL, true);
+}
+
+void
+UnityMTGrabHandlesScreen::addHandleWindow (Unity::MT::GrabHandle *h, Window w)
+{
+ mInputHandles.insert (std::pair <Window, Unity::MT::GrabHandle *> (w, h));
+}
+
+void
+UnityMTGrabHandlesScreen::removeHandleWindow (Window w)
+{
+ mInputHandles.erase (w);
+}
+
+void
+UnityMTGrabHandlesScreen::addHandles (Unity::MT::GrabHandleGroup *handles)
+{
+ mGrabHandles.push_back (handles);
+}
+
+void
+UnityMTGrabHandlesScreen::removeHandles (Unity::MT::GrabHandleGroup *handles)
+{
+ mGrabHandles.remove (handles);
+
+ mMoreAnimate = true;
+}
+
+bool
+UnityMTGrabHandlesScreen::toggleHandles (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w = screen->findWindow (CompOption::getIntOptionNamed (options,
+ "window",
+ 0));
+ if (w)
+ {
+ UMTGH_WINDOW (w);
+
+ if (!uw->allowHandles ())
+ return false;
+
+ if (uw->handlesVisible ())
+ uw->hideHandles ();
+ else
+ uw->showHandles (true);
+
+ mMoreAnimate = true;
+ }
+
+ return true;
+}
+
+bool
+UnityMTGrabHandlesScreen::showHandles (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w = screen->findWindow (CompOption::getIntOptionNamed (options,
+ "window",
+ 0));
+
+ bool use_timer = CompOption::getBoolOptionNamed (options, "use-timer", true);
+
+ if (w)
+ {
+ UMTGH_WINDOW (w);
+
+ if (!uw->allowHandles ())
+ return false;
+
+ uw->showHandles (use_timer);
+
+ if (!uw->handlesVisible ())
+ mMoreAnimate = true;
+ }
+
+ return true;
+}
+
+bool
+UnityMTGrabHandlesScreen::hideHandles (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options)
+{
+ CompWindow *w = screen->findWindow (CompOption::getIntOptionNamed (options,
+ "window",
+ 0));
+ if (w)
+ {
+ UMTGH_WINDOW (w);
+
+ if (!uw->allowHandles ())
+ return false;
+
+ if (uw->handlesVisible ())
+ {
+ uw->hideHandles ();
+ mMoreAnimate = true;
+ }
+ }
+
+ return true;
+}
+
+UnityMTGrabHandlesScreen::UnityMTGrabHandlesScreen (CompScreen *s) :
+ PluginClassHandler <UnityMTGrabHandlesScreen, CompScreen> (s),
+ cScreen (CompositeScreen::get (s)),
+ gScreen (GLScreen::get (s)),
+ mGrabHandles (0),
+ mHandleTextures (0),
+ mLastClientListStacking (screen->clientList (true)),
+ mCompResizeWindowAtom (XInternAtom (screen->dpy (),
+ "_COMPIZ_RESIZE_NOTIFY", 0)),
+ mMoreAnimate (false)
+{
+ ScreenInterface::setHandler (s);
+ CompositeScreenInterface::setHandler (cScreen);
+ GLScreenInterface::setHandler (gScreen);
+
+ mHandleTextures.resize (NUM_HANDLES);
+
+ for (unsigned int i = 0; i < NUM_HANDLES; i++)
+ {
+ CompString fname = "handle-";
+ CompString pname ("unitymtgrabhandles");
+
+ fname = compPrintf ("%s%i.png", fname.c_str (), i);
+ mHandleTextures.at (i).first =
+ GLTexture::readImageToTexture (fname, pname,
+ mHandleTextures.at (i).second);
+ }
+
+ optionSetToggleHandlesKeyInitiate (boost::bind (&UnityMTGrabHandlesScreen::toggleHandles, this, _1, _2, _3));
+ optionSetShowHandlesKeyInitiate (boost::bind (&UnityMTGrabHandlesScreen::showHandles, this, _1, _2, _3));
+ optionSetHideHandlesKeyInitiate (boost::bind (&UnityMTGrabHandlesScreen::hideHandles, this, _1, _2, _3));
+}
+
+UnityMTGrabHandlesScreen::~UnityMTGrabHandlesScreen ()
+{
+ while (mGrabHandles.size ())
+ {
+ Unity::MT::GrabHandleGroup *handles = mGrabHandles.back ();
+ delete handles;
+ mGrabHandles.pop_back ();
+ }
+
+ mHandleTextures.clear ();
+}
+
+UnityMTGrabHandlesWindow::UnityMTGrabHandlesWindow (CompWindow *w) :
+ PluginClassHandler <UnityMTGrabHandlesWindow, CompWindow> (w),
+ window (w),
+ cWindow (CompositeWindow::get (w)),
+ gWindow (GLWindow::get (w)),
+ mHandles (NULL)
+{
+ WindowInterface::setHandler (window);
+ CompositeWindowInterface::setHandler (cWindow);
+ GLWindowInterface::setHandler (gWindow);
+
+ // hack
+ _mt_screen = UnityMTGrabHandlesScreen::get (screen);
+ _timer_handle = 0;
+}
+
+UnityMTGrabHandlesWindow::~UnityMTGrabHandlesWindow ()
+{
+ if (_timer_handle)
+ g_source_remove (_timer_handle);
+
+ if (mHandles)
+ {
+ UnityMTGrabHandlesScreen::get (screen)->removeHandles (mHandles);
+ delete mHandles;
+
+ mHandles = NULL;
+ }
+}
+
+bool
+UnityMTGrabHandlesPluginVTable::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/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h
new file mode 100644
index 000000000..7acb957bb
--- /dev/null
+++ b/plugins/unity-mt-grab-handles/src/unity-mt-grab-handles.h
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2011 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authored by: Sam Spilsbury <sam.spilsbury@canonical.com>
+ */
+
+
+#include <glib.h>
+#include <core/core.h>
+#include <composite/composite.h>
+#include <opengl/opengl.h>
+
+#include <core/atoms.h>
+
+#include "unitymtgrabhandles_options.h"
+
+namespace Unity
+{
+ namespace MT
+ {
+ typedef std::pair <GLTexture::List, CompSize> TextureSize;
+ typedef std::pair <GLTexture::List *, CompRect *> TextureLayout;
+
+
+ class GrabHandle :
+ public CompRect
+ {
+ public:
+
+ GrabHandle (TextureSize *texture, Window owner, unsigned int id);
+ ~GrabHandle ();
+
+ void handleButtonPress (XButtonEvent *ev);
+ void reposition (CompPoint *p, bool);
+
+ void show ();
+ void hide ();
+
+ TextureLayout layout ();
+
+ private:
+
+ Window mIpw;
+ Window mOwner;
+ TextureSize *mTexture;
+ unsigned int mId;
+ };
+
+ class GrabHandleGroup :
+ public std::vector <Unity::MT::GrabHandle>
+ {
+ public:
+
+ GrabHandleGroup (Window owner);
+ ~GrabHandleGroup ();
+
+ void relayout (const CompRect &, bool);
+ void restack ();
+
+ bool visible ();
+ bool animate (unsigned int);
+ bool needsAnimate ();
+
+ int opacity ();
+
+ void hide ();
+ void show ();
+
+ std::vector <TextureLayout> layout ();
+
+ private:
+
+ typedef enum _state {
+ FADE_IN = 1,
+ FADE_OUT,
+ NONE
+ } State;
+
+ State mState;
+ int mOpacity;
+
+ bool mMoreAnimate;
+ };
+ };
+};
+
+class UnityMTGrabHandlesScreen :
+ public PluginClassHandler <UnityMTGrabHandlesScreen, CompScreen>,
+ public ScreenInterface,
+ public CompositeScreenInterface,
+ public GLScreenInterface,
+ public UnitymtgrabhandlesOptions
+{
+ public:
+
+ UnityMTGrabHandlesScreen (CompScreen *);
+ ~UnityMTGrabHandlesScreen ();
+
+ CompositeScreen *cScreen;
+ GLScreen *gScreen;
+
+ public:
+
+ void handleEvent (XEvent *);
+
+ bool toggleHandles (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options);
+
+ bool showHandles (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options);
+
+ bool hideHandles (CompAction *action,
+ CompAction::State state,
+ CompOption::Vector &options);
+
+ void addHandles (Unity::MT::GrabHandleGroup *handles);
+ void removeHandles (Unity::MT::GrabHandleGroup *handles);
+
+ void addHandleWindow (Unity::MT::GrabHandle *, Window);
+ void removeHandleWindow (Window);
+
+ void preparePaint (int);
+ void donePaint ();
+
+ std::vector <Unity::MT::TextureSize> & textures () { return mHandleTextures; }
+
+ private:
+
+ std::list <Unity::MT::GrabHandleGroup *> mGrabHandles;
+ std::vector <Unity::MT::TextureSize> mHandleTextures;
+
+ std::map <Window, Unity::MT::GrabHandle *> mInputHandles;
+ CompWindowVector mLastClientListStacking;
+ Atom mCompResizeWindowAtom;
+
+ bool mMoreAnimate;
+
+ // hack
+ friend class UnityMTGrabHandlesWindow;
+};
+
+#define UMTGH_SCREEN(screen) \
+ UnityMTGrabHandlesScreen *us = UnityMTGrabHandlesScreen::get (screen)
+
+class UnityMTGrabHandlesWindow :
+ public PluginClassHandler <UnityMTGrabHandlesWindow, CompWindow>,
+ public WindowInterface,
+ public CompositeWindowInterface,
+ public GLWindowInterface
+{
+ public:
+
+ UnityMTGrabHandlesWindow (CompWindow *);
+ ~UnityMTGrabHandlesWindow ();
+
+ CompWindow *window;
+ CompositeWindow *cWindow;
+ GLWindow *gWindow;
+
+ public:
+
+ bool allowHandles ();
+ bool handleTimerActive ();
+
+ void grabNotify (int, int, unsigned int, unsigned int);
+ void ungrabNotify ();
+
+ void relayout (const CompRect &, bool);
+
+ void getOutputExtents (CompWindowExtents &output);
+
+ void moveNotify (int dx, int dy, bool immediate);
+
+ bool glDraw (const GLMatrix &,
+ GLFragment::Attrib &,
+ const CompRegion &,
+ unsigned int);
+
+ bool handlesVisible ();
+ void hideHandles ();
+ void showHandles (bool use_timer);
+ void restackHandles ();
+
+ void resetTimer ();
+ void disableTimer ();
+
+ private:
+
+ static gboolean onHideTimeout (gpointer data);
+
+ Unity::MT::GrabHandleGroup *mHandles;
+ UnityMTGrabHandlesScreen *_mt_screen;
+ guint _timer_handle;
+
+ friend class Unity::MT::GrabHandle;
+};
+
+#define UMTGH_WINDOW(window) \
+ UnityMTGrabHandlesWindow *uw = UnityMTGrabHandlesWindow::get (window)
+
+class UnityMTGrabHandlesPluginVTable :
+ public CompPlugin::VTableForScreenAndWindow <UnityMTGrabHandlesScreen,
+ UnityMTGrabHandlesWindow>
+{
+ public:
+
+ bool init ();
+};