diff options
| author | Sam Spilsbury <sam.spilsbury@canonical.com> | 2013-02-10 09:18:30 +0800 |
|---|---|---|
| committer | Sam Spilsbury <sam.spilsbury@canonical.com> | 2013-02-10 09:18:30 +0800 |
| commit | f32c28266c0f2d9873568db71f933a280d9cc7da (patch) | |
| tree | d2d18b28061b1cb3ef59bb2782044b3e5b2740a4 /plugins/unityshell | |
| parent | ac0e2f55e99c11a95fdd15dc7b6b77abd2e26a00 (diff) | |
| parent | 5c40621cbeb4ecd831a8af447beb1fd3988327fe (diff) | |
Merge unity.fix_851964
(bzr r2998.6.2)
Diffstat (limited to 'plugins/unityshell')
| -rw-r--r-- | plugins/unityshell/src/inputremover.cpp | 442 | ||||
| -rw-r--r-- | plugins/unityshell/src/inputremover.h | 49 | ||||
| -rw-r--r-- | plugins/unityshell/src/minimizedwindowhandler.cpp | 1 | ||||
| -rw-r--r-- | plugins/unityshell/src/unityshell.cpp | 16 |
4 files changed, 475 insertions, 33 deletions
diff --git a/plugins/unityshell/src/inputremover.cpp b/plugins/unityshell/src/inputremover.cpp index a6798721d..42a02d136 100644 --- a/plugins/unityshell/src/inputremover.cpp +++ b/plugins/unityshell/src/inputremover.cpp @@ -19,19 +19,77 @@ * Sam Spilsbury <sam.spilsbury@canonical.com> */ +#include <cstdlib> + #include "inputremover.h" #include <X11/Xregion.h> #include <cstdio> #include <cstring> +namespace +{ +const unsigned int propVersion = 1; + +void CheckRectanglesCount(XRectangle *rects, + int *count, + unsigned int width, + unsigned int height, + unsigned int border) +{ + /* check if the returned shape exactly matches the window shape - + * if that is true, the window currently has no set input shape */ + if ((*count == 1) && + (rects[0].x == -((int) border)) && + (rects[0].y == -((int) border)) && + (rects[0].width == (width + border)) && + (rects[0].height == (height + border))) + { + *count = 0; + } +} + +bool CheckWindowExists(Display *dpy, Window shapeWindow, + unsigned int *width, + unsigned int *height, + unsigned int *border) +{ + Window root; + int x, y; + unsigned int depth; + + + /* FIXME: There should be a generic GetGeometry request we can + * use here in order to avoid a round-trip */ + if (!XGetGeometry (dpy, shapeWindow, &root, &x, &y, width, height, + border, &depth)) + { + return false; + } + + return true; +} + +XRectangle * QueryRectangles(Display *dpy, Window shapeWindow, + int *count, + int *ordering, + int kind) +{ + return XShapeGetRectangles (dpy, shapeWindow, kind, + count, ordering); +} + +} + compiz::WindowInputRemoverInterface::~WindowInputRemoverInterface () { } compiz::WindowInputRemover::WindowInputRemover (Display *dpy, - Window xid) : + Window shapeWindow, + Window propWindow) : mDpy (dpy), - mShapeWindow (xid), + mShapeWindow (shapeWindow), + mPropWindow (propWindow), mShapeMask (0), mInputRects (NULL), mNInputRects (0), @@ -43,12 +101,54 @@ compiz::WindowInputRemover::WindowInputRemover (Display *dpy, { /* FIXME: roundtrip */ XShapeQueryExtension (mDpy, &mShapeEvent, &mShapeError); + + /* Check to see if the propWindow has a saved shape, + * if so, it means that we are coming from a restart or + * a crash where it wasn't properly restored, so we need + * to restore the saved input shape before doing anything + */ + XRectangle *bRects, *iRects; + int bCount = 0, iCount = 0, bOrdering, iOrdering; + + if (queryProperty(&iRects, &iCount, &iOrdering, + &bRects, &bCount, &bOrdering)) + { + bool rectangles_restored = false; + unsigned int width, height, border; + + if (CheckWindowExists(mDpy, mShapeWindow, &width, &height, &border)) + if (checkRectangles(iRects, &iCount, iOrdering, + bRects, &bCount, bOrdering, + width, height, border)) + if (saveRectangles(iRects, iCount, iOrdering, + bRects, bCount, bOrdering)) + { + /* Tell the shape restore engine that we've got a removed + * input shape here */ + mRemoved = true; + if (restoreInput()) + rectangles_restored = true; + } + + /* Something failed and we couldn't restore the + * rectangles. Don't leak them */ + if (!rectangles_restored) + { + free (iRects); + free (bRects); + } + } + } compiz::WindowInputRemover::~WindowInputRemover () { if (mRemoved) restore (); + + /* Remove the window property as we have already successfully restored + * the window shape */ + clearProperty(); } void @@ -207,42 +307,323 @@ compiz::WindowInputRemover::sendShapeNotify () } bool -compiz::WindowInputRemover::saveInput () +compiz::WindowInputRemover::checkRectangles(XRectangle *input, + int *nInput, + int inputOrdering, + XRectangle *bounding, + int *nBounding, + int boundingOrdering, + unsigned int width, + unsigned int height, + unsigned int border) { - XRectangle *rects; - int count = 0, ordering; - Window root; - int x, y; - unsigned int width, height, border, depth; + CheckRectanglesCount(input, nInput, width, height, border); + CheckRectanglesCount(bounding, nBounding, width, height, border); - /* FIXME: There should be a generic GetGeometry request we can - * use here in order to avoid a round-trip */ - if (!XGetGeometry (mDpy, mShapeWindow, &root, &x, &y, &width, &height, - &border, &depth)) + /* There may be other sanity checks in future */ + return true; +} + +bool +compiz::WindowInputRemover::queryShapeRectangles(XRectangle **input, + int *nInput, + int *inputOrdering, + XRectangle **bounding, + int *nBounding, + int *boundingOrdering, + unsigned int *width, + unsigned int *height, + unsigned int *border) +{ + + if (!CheckWindowExists(mDpy, mShapeWindow, width, height, border)) + return false; + + *input = QueryRectangles(mDpy, mShapeWindow, + nInput, inputOrdering, ShapeInput); + + *bounding = QueryRectangles(mDpy, mShapeWindow, + nBounding, boundingOrdering, ShapeBounding); + + return true; +} + +bool +compiz::WindowInputRemover::saveRectangles(XRectangle *input, + int nInput, + int inputOrdering, + XRectangle *bounding, + int nBounding, + int boundingOrdering) +{ + if (mInputRects) + XFree (mInputRects); + + mInputRects = input; + mNInputRects = nInput; + mInputRectOrdering = inputOrdering; + + if (mBoundingRects) + XFree (mBoundingRects); + + mBoundingRects = bounding; + mNBoundingRects = nBounding; + mBoundingRectOrdering = boundingOrdering; + + return true; +} + +void +compiz::WindowInputRemover::clearRectangles () +{ + /* Revert save action to local memory */ + if (mBoundingRects) + XFree (mBoundingRects); + + mNBoundingRects = 0; + mBoundingRectOrdering = 0; + + if (mInputRects) + XFree (mInputRects); + + mNInputRects = 0; + mInputRectOrdering = 0; + + mShapeMask = 0; + + mRemoved = false; +} + +bool +compiz::WindowInputRemover::writeProperty (XRectangle *input, + int nInput, + int inputOrdering, + XRectangle *bounding, + int nBounding, + int boundingOrdering) +{ + Atom prop = XInternAtom (mDpy, "_UNITY_SAVED_WINDOW_SHAPE", FALSE); + Atom type = XA_CARDINAL; + int fmt = 32; + + const unsigned int headerSize = 5; + + /* + * -> version + * -> nInput + * -> inputOrdering + * -> nBounding + * -> boundingOrdering + * + * + + * + * nRectangles * 4 + */ + const size_t dataSize = headerSize + (nInput * 4) + (nBounding * 4); + + unsigned long data[dataSize]; + + data[0] = propVersion; + data[1] = nInput; + data[2] = inputOrdering; + data[3] = nBounding; + data[4] = boundingOrdering; + + for (int i = 0; i < nInput; ++i) + { + const unsigned int position = dataSize + (i * 4); + + data[position + 0] = input[i].x; + data[position + 1] = input[i].y; + data[position + 2] = input[i].width; + data[position + 3] = input[i].height; + } + + for (int i = 0; i < nBounding; ++i) + { + const unsigned int position = dataSize + (i * 4) + nBounding * 4; + + data[position + 0] = bounding[i].x; + data[position + 1] = bounding[i].y; + data[position + 2] = bounding[i].width; + data[position + 3] = bounding[i].height; + } + + /* No need to check return code, always returns 0 */ + XChangeProperty(mDpy, + mPropWindow, + prop, + type, + fmt, + PropModeReplace, + reinterpret_cast<unsigned char*>(data), + dataSize); + + return true; +} + +bool +compiz::WindowInputRemover::queryProperty(XRectangle **input, + int *nInput, + int *inputOrdering, + XRectangle **bounding, + int *nBounding, + int *boundingOrdering) + +{ + Atom prop = XInternAtom (mDpy, "_UNITY_SAVED_WINDOW_SHAPE", FALSE); + Atom type = XA_CARDINAL; + int fmt = 32; + + Atom actualType; + int actualFmt; + + unsigned long nItems; + unsigned long nLeft; + + unsigned char *propData; + + const unsigned long headerLength = 5L; + + /* First query the first five bytes to figure out how + * long the rest of the property is going to be */ + if (!XGetWindowProperty(mDpy, + mPropWindow, + prop, + 0L, + headerLength, + FALSE, + type, + &actualType, + &actualFmt, + &nItems, + &nLeft, + &propData)) { return false; } - rects = XShapeGetRectangles (mDpy, mShapeWindow, ShapeInput, - &count, &ordering); + /* If type or format is mismatched, return false */ + if (actualType != type || + actualFmt != fmt || + headerLength != nItems) + { + XFree (propData); + return false; + } - /* check if the returned shape exactly matches the window shape - - * if that is true, the window currently has no set input shape */ - if ((count == 1) && - (rects[0].x == -((int) border)) && - (rects[0].y == -((int) border)) && - (rects[0].width == (width + border)) && - (rects[0].height == (height + border))) + unsigned long *headerData = reinterpret_cast<unsigned long *>(propData); + + /* If version is mismatched, return false */ + if (headerData[0] != propVersion) + return false; + + /* New length is nInput * 4 + nBounding * 4 + headerSize */ + unsigned long fullLength = *nInput * 4 + *nBounding * 4 + headerLength; + + /* Free data and get the rest */ + XFree (propData); + + if (!XGetWindowProperty(mDpy, + mPropWindow, + prop, + 0L, + fullLength, + FALSE, + type, + &actualType, + &actualFmt, + &nItems, + &nLeft, + &propData)) { - count = 0; + return false; } - if (mInputRects) - XFree (mInputRects); + /* Check to make sure we got everything */ + if (fullLength != nItems) + { + printf ("warning, did not get full legnth"); + return false; + } - mInputRects = rects; - mNInputRects = count; - mInputRectOrdering = ordering; + unsigned long *data = reinterpret_cast<unsigned long *>(propData); + + /* Read in the header */ + *nInput = data[1]; + *inputOrdering = data[2]; + *nBounding = data[3]; + *boundingOrdering = data[4]; + + /* Read in the rectangles */ + *input = reinterpret_cast<XRectangle *>(calloc(1, sizeof(XRectangle) * *nInput)); + + for (int i = 0; i < *nInput; ++i) + { + const unsigned int position = headerLength + i * 4; + + (*input)[i].x = data[position + 0]; + (*input)[i].y = data[position + 1]; + (*input[i]).width = data[position + 2]; + (*input[i]).height = data[position + 3]; + } + + for (int i = 0; i < *nBounding; ++i) + { + const unsigned int position = headerLength + *nInput * 4 + i * 4; + + (*bounding)[i].x = data[position + 0]; + (*bounding)[i].y = data[position + 1]; + (*bounding[i]).width = data[position + 2]; + (*bounding[i]).height = data[position + 3]; + } + + XFree (propData); + + return true; +} + +void +compiz::WindowInputRemover::clearProperty() +{ + Atom prop = XInternAtom (mDpy, "_UNITY_SAVED_WINDOW_SHAPE", FALSE); + + XDeleteProperty(mDpy, mPropWindow, prop); +} + +bool +compiz::WindowInputRemover::saveInput () +{ + XRectangle *bRects, *iRects; + int bCount = 0, iCount = 0, bOrdering, iOrdering; + unsigned int width, height, border; + + /* Never save input for a cleared window */ + if (mRemoved) + return false; + + if (!queryShapeRectangles(&iRects, &iCount, &iOrdering, + &bRects, &bCount, &bOrdering, + &width, &height, &border)) + { + clearRectangles (); + return false; + } + + if (!checkRectangles(iRects, &iCount, iOrdering, + bRects, &bCount, bOrdering, + width, height, border)) + { + clearRectangles (); + return false; + } + + if (!writeProperty(iRects, iCount, iOrdering, + bRects, bCount, bOrdering)) + { + clearRectangles (); + return false; + } rects = XShapeGetRectangles (mDpy, mShapeWindow, ShapeBounding, &count, &ordering); @@ -267,6 +648,9 @@ compiz::WindowInputRemover::saveInput () mShapeMask = XShapeInputSelected (mDpy, mShapeWindow); + saveRectangles(iRects, iCount, iOrdering, + bRects, bCount, bOrdering); + return true; } @@ -286,10 +670,10 @@ compiz::WindowInputRemover::removeInput () XShapeSelectInput (mDpy, mShapeWindow, mShapeMask); - mRemoved = true; - sendShapeNotify (); + mRemoved = true; + return true; } diff --git a/plugins/unityshell/src/inputremover.h b/plugins/unityshell/src/inputremover.h index 69284f718..b5e87eb76 100644 --- a/plugins/unityshell/src/inputremover.h +++ b/plugins/unityshell/src/inputremover.h @@ -54,7 +54,9 @@ class WindowInputRemover : { public: - WindowInputRemover (Display *, Window xid); + WindowInputRemover (Display *, + Window shapeWindow, + Window propWindow); ~WindowInputRemover (); private: @@ -65,8 +67,53 @@ private: void sendShapeNotify (); + bool queryShapeRectangles(XRectangle **input, + int *nInput, + int *inputOrdering, + XRectangle **bounding, + int *nBounding, + int *boundingOrdering, + unsigned int *width, + unsigned int *height, + unsigned int *border); + + bool queryProperty(XRectangle **input, + int *nInput, + int *inputOrdering, + XRectangle **bounding, + int *nBounding, + int *boundingOrdering); + + bool writeProperty(XRectangle *input, + int nInput, + int inputOrdering, + XRectangle *bounding, + int nBounding, + int boundingOrdering); + + bool checkRectangles(XRectangle *input, + int *nInput, + int inputOrdering, + XRectangle *bounding, + int *nBounding, + int boundingOrdering, + unsigned int width, + unsigned int height, + unsigned int border); + + bool saveRectangles(XRectangle *input, + int nInput, + int inputOrdering, + XRectangle *bounding, + int nBounding, + int boundingOrdering); + + void clearProperty (); + void clearRectangles (); + Display *mDpy; Window mShapeWindow; + Window mPropWindow; unsigned long mShapeMask; XRectangle *mInputRects; diff --git a/plugins/unityshell/src/minimizedwindowhandler.cpp b/plugins/unityshell/src/minimizedwindowhandler.cpp index 05abef0cc..e0ec285fb 100644 --- a/plugins/unityshell/src/minimizedwindowhandler.cpp +++ b/plugins/unityshell/src/minimizedwindowhandler.cpp @@ -227,6 +227,7 @@ compiz::MinimizedWindowHandler::unminimize () int count = 0; nextStateSize = nItems; + nextState = reinterpret_cast<Atom *>(malloc(sizeof(Atom) * nextStateSize)); pbegin = nextState = (Atom *) memcpy (nextState, data, sizeof (Atom) * nextStateSize); diff --git a/plugins/unityshell/src/unityshell.cpp b/plugins/unityshell/src/unityshell.cpp index 863e395ad..b9a12cbe5 100644 --- a/plugins/unityshell/src/unityshell.cpp +++ b/plugins/unityshell/src/unityshell.cpp @@ -1136,7 +1136,11 @@ UnityWindow::GetInputRemover () if (!input_remover_.expired ()) return input_remover_.lock (); - compiz::WindowInputRemoverLock::Ptr ret (new compiz::WindowInputRemoverLock (new compiz::WindowInputRemover (screen->dpy (), window->id ()))); + compiz::WindowInputRemoverLock::Ptr + ret (new compiz::WindowInputRemoverLock ( + new compiz::WindowInputRemover (screen->dpy (), + window->id (), + window->id ()))); input_remover_ = ret; return ret; } @@ -3354,14 +3358,18 @@ UnityWindow::UnityWindow(CompWindow* window) GLWindowInterface::setHandler(gWindow); ScaleWindowInterface::setHandler (ScaleWindow::get (window)); + /* This needs to happen before we set our wrapable functions, since we + * need to ask core (and not ourselves) whether or not the window is + * minimized */ if (UnityScreen::get (screen)->optionGetShowMinimizedWindows () && window->mapNum ()) { + /* Query the core function */ + window->minimizedSetEnabled (this, false); + bool wasMinimized = window->minimized (); if (wasMinimized) window->unminimize (); - window->minimizeSetEnabled (this, true); - window->unminimizeSetEnabled (this, true); window->minimizedSetEnabled (this, true); if (wasMinimized) @@ -3374,6 +3382,8 @@ UnityWindow::UnityWindow(CompWindow* window) window->minimizedSetEnabled (this, false); } + /* Keep this after the optionGetShowMinimizedWindows branch */ + if (window->state () & CompWindowStateFullscreenMask) UnityScreen::get (screen)->fullscreen_windows_.push_back(window); |
