diff -Nru compiz-0.9.7.12/debian/changelog compiz-0.9.7.12/debian/changelog --- compiz-0.9.7.12/debian/changelog 2013-09-23 09:15:09.000000000 -0400 +++ compiz-0.9.7.12/debian/changelog 2014-07-07 15:18:16.000000000 -0400 @@ -1,3 +1,11 @@ +compiz (1:0.9.7.12-0ubuntu4) UNRELEASED; urgency=low + + * debian/patches/fix_external_monitor_hotplug.patch + - Cherry-pick fixes upstream for window mismanagement when adding + and/or removing an external monitor. (LP: #763148) (LP: #1171878) + + -- Chris Townsend Mon, 07 Jul 2014 15:15:43 -0400 + compiz (1:0.9.7.12-0ubuntu3) precise; urgency=low * debian/patches/blacklist_precise_mesa80_intel_nouveau.patch: diff -Nru compiz-0.9.7.12/debian/patches/fix_external_monitor_hotplug.patch compiz-0.9.7.12/debian/patches/fix_external_monitor_hotplug.patch --- compiz-0.9.7.12/debian/patches/fix_external_monitor_hotplug.patch 1969-12-31 19:00:00.000000000 -0500 +++ compiz-0.9.7.12/debian/patches/fix_external_monitor_hotplug.patch 2014-07-07 15:14:07.000000000 -0400 @@ -0,0 +1,588 @@ +Description: patch to fix window movement when adding/removing an external monitor + This patch fixes issues in Compiz where removing and/or adding an external + monitor will make windows appear on the wrong workspace or disappear + altogether. + +Origin: Taken from lp:compiz-core r3136 & r3137. + +Bug-Ubuntu: https://bugs.launchpad.net/bugs/763148 + https://bugs.launchpad.net/bugs/1171878 + +Index: compiz-core.precise/include/core/window.h +=================================================================== +--- compiz-core.precise.orig/include/core/window.h 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/include/core/window.h 2014-07-07 14:59:10.539004565 -0400 +@@ -490,6 +490,8 @@ + + bool alive (); + ++ bool moved () const; ++ + bool overrideRedirect (); + + bool isMapped () const; +Index: compiz-core.precise/plugins/place/src/place.cpp +=================================================================== +--- compiz-core.precise.orig/plugins/place/src/place.cpp 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/plugins/place/src/place.cpp 2014-07-07 14:59:10.539004565 -0400 +@@ -200,7 +200,9 @@ + PlaceScreen::handleEvent (XEvent *event) + { + if (event->type == ConfigureNotify && +- event->xconfigure.window == screen->root ()) ++ event->xconfigure.window == screen->root () && ++ (event->xconfigure.width != screen->width () || ++ event->xconfigure.height != screen->height ())) + { + mPrevSize.setWidth (screen->width ()); + mPrevSize.setHeight (screen->height ()); +@@ -300,6 +302,14 @@ + + PlaceWindow::~PlaceWindow () + { ++ if (!ps->mStrutWindows.empty() && window->struts()) ++ { ++ ps->mStrutWindows.remove(window); ++ if (ps->mStrutWindows.empty()) ++ { ++ ps->doHandleScreenSizeChange(screen->width(), screen->height()); ++ } ++ } + } + + bool +Index: compiz-core.precise/plugins/place/src/screen-size-change/src/screen-size-change.cpp +=================================================================== +--- compiz-core.precise.orig/plugins/place/src/screen-size-change/src/screen-size-change.cpp 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/plugins/place/src/screen-size-change/src/screen-size-change.cpp 2014-07-07 14:59:10.539004565 -0400 +@@ -37,11 +37,9 @@ + compiz::place::ScreenSizeChangeObject::adjustForSize (const CompSize &oldSize, + const CompSize &newSize) + { +- int vpX, vpY, shiftX, shiftY; ++ int vpX, vpY; + compiz::window::Geometry g, vpRelRect; + int pivotX, pivotY; +- int curVpOffsetX = getViewport ().x () * newSize.width (); +- int curVpOffsetY = getViewport ().y () * newSize.height (); + + g = getGeometry (); + compiz::window::Geometry og (g); +@@ -59,24 +57,14 @@ + if (pivotY < 0) + vpY -= 1; + +- /* if window's target vp is to the left of the leftmost viewport on that +- row, assign its target vp column as 0 (-s->x rel. to current vp) */ +- if (getViewport ().x () + vpX < 0) +- vpX = -getViewport ().x (); +- +- /* if window's target vp is above the topmost viewport on that column, +- assign its target vp row as 0 (-s->y rel. to current vp) */ +- if (getViewport ().y () + vpY < 0) +- vpY = -getViewport ().y (); +- + unsigned int mask = mSaver.pop (vpRelRect, CHANGE_X | CHANGE_Y | + CHANGE_WIDTH | CHANGE_HEIGHT); + + if (mask) + { + /* set position/size to saved original rectangle */ +- g.applyChange (compiz::window::Geometry (vpRelRect.x () + vpX * newSize.width (), +- vpRelRect.y () + vpY * newSize.height (), ++ g.applyChange (compiz::window::Geometry (vpRelRect.x (), ++ vpRelRect.y (), + vpRelRect.width (), + vpRelRect.height (), + vpRelRect.border ()), mask); +@@ -90,42 +78,24 @@ + vpRelRect.setWidth (g.width ()); + vpRelRect.setHeight (g.height ()); + +- g.setPos (g.pos ()); +- +- shiftX = vpX * (newSize.width () - oldSize.width ()); +- shiftY = vpY * (newSize.width () - oldSize.height ()); ++ g = vpRelRect; + + /* if coords. relative to viewport are outside new viewport area, + shift window left/up so that it falls inside */ +- if (vpRelRect.x () >= newSize.width ()) +- shiftX -= vpRelRect.x () - (newSize.width () - 1); +- if (vpRelRect.y () >= newSize.height ()) +- shiftY -= vpRelRect.y () - (newSize.height () - 1); +- +- if (shiftX) +- g.setX (g.x () + shiftX); +- +- if (shiftY) +- g.setY (g.y () + shiftY); ++ if (vpRelRect.x () + vpRelRect.width() >= newSize.width ()) ++ g.setX (g.x () - (vpRelRect.x () + vpRelRect.width () - newSize.width ())); ++ if (vpRelRect.y () + vpRelRect.height() >= newSize.height ()) ++ g.setY (g.y () - (vpRelRect.y () + vpRelRect.width () - newSize.height ())); + + g.setWidth (vpRelRect.width ()); + g.setHeight (vpRelRect.height ()); + } + +- /* Handle non-(0,0) current viewport by shifting by curVpOffsetX,Y, +- and bring window to (0,0) by shifting by minus its vp offset */ +- +- g.setX (g.x () + curVpOffsetX - (getViewport ().x () + vpX) * newSize.width ()); +- g.setY (g.y () + curVpOffsetY - (getViewport ().y () + vpY) * newSize.height ()); +- + unsigned int flags = 0; + const CompRect &workArea = getWorkarea (g); + + compiz::place::clampGeometryToWorkArea (g, workArea, getExtents (), flags, newSize); + +- g.setX (g.x () - curVpOffsetX + (getViewport ().x () + vpX) * newSize.width ()); +- g.setY (g.y () - curVpOffsetY + (getViewport ().y () + vpY) * newSize.height ()); +- + if (!mask) + { + /* save window geometry (relative to viewport) so that it +@@ -151,6 +121,9 @@ + mSaver.push (vpRelRect, remaining); + } + ++ g.setX (g.x () + vpX * newSize.width ()); ++ g.setY (g.y () + vpY * newSize.height ()); ++ + /* for maximized/fullscreen windows, update saved pos/size XXX, + * also pull in the old code to handle maximized windows which + * currently can't be implemented yet */ +Index: compiz-core.precise/plugins/place/src/screen-size-change/tests/screen-size-change/src/test-place-screen-size-change.cpp +=================================================================== +--- compiz-core.precise.orig/plugins/place/src/screen-size-change/tests/screen-size-change/src/test-place-screen-size-change.cpp 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/plugins/place/src/screen-size-change/tests/screen-size-change/src/test-place-screen-size-change.cpp 2014-07-07 14:59:10.543004564 -0400 +@@ -57,6 +57,9 @@ + unsigned int bottom); + + void setGeometry (const compiz::window::Geometry &g); ++ compiz::window::Geometry sizeAdjustTest (const CompSize &oldSize, ++ const CompSize &newSize, ++ CompRect &workArea); + + private: + +@@ -162,21 +165,34 @@ + workArea.setBottom (workArea.bottom () - 24); + } + ++compiz::window::Geometry ++MockScreenSizeChangeObject::sizeAdjustTest (const CompSize &oldSize, ++ const CompSize &newSize, ++ CompRect &workArea) ++{ ++ /* Reserve top, bottom and left parts of the screen for ++ * fake "24px" panels */ ++ reserveStruts (workArea); ++ ++ setWorkArea (workArea); ++ ++ compiz::window::Geometry g = adjustForSize (oldSize, newSize); ++ ++ return g; ++} ++ ++ + TEST_F(CompPlaceScreenSizeChangeTestScreenSizeChange, TestScreenSizeChange) + { + CompSize current, old; + compiz::window::Geometry g (200, 250, 300, 400, 0); ++ compiz::window::Geometry expected; + +- MockScreenSizeChangeObject *ms = new MockScreenSizeChangeObject (g); ++ MockScreenSizeChangeObject ms (g); + + current = CompSize (1280, 800); + +- /* Reserve top, bottom and left parts of the screen for +- * fake "24px" panels */ +- CompRect workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); +- +- ms->setWorkArea (workArea); ++ CompRect workArea; + + /* First test that changing the screen size + * to something smaller here doesn't cause our +@@ -184,115 +200,101 @@ + + old = current; + current = CompSize (1024, 768); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); + +- ms->setWorkArea (workArea); ++ expected = compiz::window::Geometry (200, 250, 300, 400, 0); + +- g = ms->adjustForSize (old, current); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- EXPECT_EQ (g, compiz::window::Geometry (200, 250, 300, 400, 0)); ++ EXPECT_EQ (expected, g); + + /* Making the screen size bigger with no + * saved geometry should cause the window not to move */ +- + old = current; + current = CompSize (2048, 768); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); + +- ms->setWorkArea (workArea); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- g = ms->adjustForSize (old, current); +- +- EXPECT_EQ (g, compiz::window::Geometry (200, 250, 300, 400, 0)); ++ EXPECT_EQ (expected, g); + + /* Move the window to the other "monitor" */ +- +- ms->setGeometry (compiz::window::Geometry (1025, 250, 300, 400, 0)); +- +- old = current; ++ ms.setGeometry (compiz::window::Geometry (1025, 250, 300, 400, 0)); + + /* Unplug a "monitor" */ ++ old = current; + current = CompSize (1024, 768); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); + +- ms->setWorkArea (workArea); ++ expected = compiz::window::Geometry (724, 250, 300, 400, 0); + +- g = ms->adjustForSize (old, current); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- EXPECT_EQ (g, compiz::window::Geometry (724, 250, 300, 400, 0)); +- +- old = current; ++ EXPECT_EQ (expected, g); + + /* Re-plug the monitor - window should go back + * to the same position */ ++ old = current; + current = CompSize (2048, 768); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); +- +- ms->setWorkArea (workArea); + +- g = ms->adjustForSize (old, current); ++ expected = compiz::window::Geometry (1025, 250, 300, 400, 0); + +- EXPECT_EQ (g, compiz::window::Geometry (1025, 250, 300, 400, 0)); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- old = current; ++ EXPECT_EQ (expected, g); + + /* Plug 2 monitors downwards, no change */ ++ old = current; + current = CompSize (2048, 1536); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); + +- ms->setWorkArea (workArea); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- g = ms->adjustForSize (old, current); +- +- EXPECT_EQ (g, compiz::window::Geometry (1025, 250, 300, 400, 0)); ++ EXPECT_EQ (expected, g); + + /* Move the window to the bottom "monitor" */ +- +- ms->setGeometry (compiz::window::Geometry (1025, 791, 300, 400, 0)); +- +- old = current; ++ ms.setGeometry (compiz::window::Geometry (1025, 791, 300, 400, 0)); + + /* Unplug bottom "monitor" */ ++ old = current; + current = CompSize (2048, 768); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); +- +- ms->setWorkArea (workArea); + +- g = ms->adjustForSize (old, current); ++ expected = compiz::window::Geometry (1025, 344, 300, 400, 0); + +- EXPECT_EQ (g, compiz::window::Geometry (1025, 344, 300, 400, 0)); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- old = current; ++ EXPECT_EQ (expected, g); + + /* Re-plug bottom "monitor" */ ++ old = current; + current = CompSize (2048, 1356); +- + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); + +- ms->setWorkArea (workArea); ++ expected = compiz::window::Geometry (1025, 791, 300, 400, 0); + +- g = ms->adjustForSize (old, current); ++ g = ms.sizeAdjustTest (old, current, workArea); + +- EXPECT_EQ (g, compiz::window::Geometry (1025, 791, 300, 400, 0)); ++ EXPECT_EQ (expected, g); + +- /* Move the entire window right a viewport */ ++} + +- g.setPos (g.pos () + CompPoint (current.width (), 0)); ++TEST_F(CompPlaceScreenSizeChangeTestScreenSizeChange, TestScreenChangeWindowsOnSecondViewport) ++{ ++ CompSize current, old; ++ compiz::window::Geometry g (1025, 791, 300, 400, 0); ++ compiz::window::Geometry expected; ++ ++ MockScreenSizeChangeObject ms (g); ++ ++ current = CompSize (2048, 1356); + +- ms->setGeometry (g); ++ CompRect workArea; ++ ++ /* Move the entire window right a viewport */ ++ g.setPos (g.pos () + CompPoint (current.width (), 0)); ++ ms.setGeometry (g); + + /* Now change the screen resolution again - the window should + * move to be within the constrained size of its current +@@ -301,14 +303,115 @@ + /* Unplug a "monitor" */ + old = current; + current = CompSize (1024, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ expected = compiz::window::Geometry (current.width () + 724, 791, 300, 400, 0); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); + ++ /* Replug the monitor, make sure that the geometry is restored */ ++ old = current; ++ current = CompSize (2048, 1356); + workArea = CompRect (0, 0, current.width (), current.height ()); +- reserveStruts (workArea); + +- ms->setWorkArea (workArea); ++ expected = compiz::window::Geometry (current.width () + 1025, 791, 300, 400, 0); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); ++ ++ /* Replug the monitor and move the window to where it fits on the first ++ * monitor on the second viewport, then make sure it doesn't move */ ++ old = CompSize (2048, 1356); ++ current = CompSize (1024, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ g.setPos (CompPoint (old.width () + 25, 791)); ++ ms.setGeometry (g); ++ /* clear the saved geometry */ ++ ms.unset(); ++ ++ expected = compiz::window::Geometry (current.width () + 25, 791, 300, 400, 0); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); + +- g = ms->adjustForSize (old, current); ++ EXPECT_EQ (expected, g); + +- EXPECT_EQ (g, compiz::window::Geometry (current.width () + 724, 791, 300, 400, 0)); ++ old = current; ++ current = CompSize (2048, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ expected = compiz::window::Geometry (current.width () + 25, 791, 300, 400, 0); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); + } + ++TEST_F(CompPlaceScreenSizeChangeTestScreenSizeChange, TestScreenChangeWindowsOnPreviousViewport) ++{ ++ CompSize current, old; ++ compiz::window::Geometry g (0, 0, 300, 400, 0); ++ compiz::window::Geometry expected; ++ ++ MockScreenSizeChangeObject ms (g); ++ ++ current = CompSize (2048, 1356); ++ ++ CompRect workArea; ++ ++ /* Deal with the case where the position is negative, which means ++ * it's actually wrapped around to the rightmost viewport ++ */ ++ g.setPos (CompPoint (-300, 200)); ++ ms.setGeometry (g); ++ ++ expected = g; ++ ++ /* Unplug the right "monitor" */ ++ old = current; ++ current = CompSize (1024, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); ++ ++ /* Re-plug the right "monitor" */ ++ old = current; ++ current = CompSize (2048, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); ++ ++ /* Move the window to the left monitor, verify that it survives an ++ * unplug/plug cycle ++ */ ++ g.setPos (CompPoint (-1324, 200)); ++ ms.setGeometry (g); ++ ++ old = current; ++ current = CompSize (1024, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ expected = compiz::window::Geometry (-300, 200, 300, 400, 0); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); ++ ++ old = current; ++ current = CompSize (2048, 1356); ++ workArea = CompRect (0, 0, current.width (), current.height ()); ++ ++ expected = compiz::window::Geometry (-1324, 200, 300, 400, 0); ++ ++ g = ms.sizeAdjustTest (old, current, workArea); ++ ++ EXPECT_EQ (expected, g); ++ ++} +Index: compiz-core.precise/src/privatewindow.h +=================================================================== +--- compiz-core.precise.orig/src/privatewindow.h 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/src/privatewindow.h 2014-07-07 14:59:10.543004564 -0400 +@@ -302,6 +302,8 @@ + unsigned int lastPong; + bool alive; + ++ bool moved; ++ + CompWindowExtents input; + CompWindowExtents serverInput; + CompWindowExtents border; +Index: compiz-core.precise/src/screen.cpp +=================================================================== +--- compiz-core.precise.orig/src/screen.cpp 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/src/screen.cpp 2014-07-07 14:59:10.543004564 -0400 +@@ -3566,10 +3566,24 @@ + + if (workAreaChanged) + { ++ CompWindow::Geometry before, after; ++ + /* as work area changed, update all maximized windows on this + screen to snap to the new work area */ + foreach (CompWindow *w, priv->windows) ++ { ++ before = w->priv->serverGeometry; + w->priv->updateSize (); ++ after = w->priv->serverGeometry; ++ ++ /* A maximized window was adjusted for the new workarea size */ ++ if (before != after && ++ (w->state () & CompWindowStateMaximizedVertMask || ++ w->state () & CompWindowStateMaximizedHorzMask)) ++ { ++ w->priv->moved = true; ++ } ++ } + } + } + +Index: compiz-core.precise/src/window.cpp +=================================================================== +--- compiz-core.precise.orig/src/window.cpp 2014-07-07 14:56:34.972412000 -0400 ++++ compiz-core.precise/src/window.cpp 2014-07-07 14:59:10.547004564 -0400 +@@ -3903,6 +3903,31 @@ + mask |= restoreGeometry (xwc, CWX | CWWidth); + } + ++ /* Check to see if a monitor has disappeared that had a maximized window and if so, ++ * adjust the window to restore in the current viewport instead of the ++ * coordinates of a different viewport. */ ++ if (window->moved () && ++ !(state & CompWindowStateMaximizedVertMask || state & CompWindowStateMaximizedHorzMask)) ++ { ++ if (xwc->x > screen->width () || ++ xwc->y > screen->height ()) ++ { ++ /* The removed monitor may have had a much different resolution than the ++ * the current monitor, so let's just orient the window in the top left ++ * of the workarea. */ ++ xwc->x = workArea.x () + window->border ().left; ++ xwc->y = workArea.y () + window->border ().top; ++ ++ if (xwc->width > workArea.width ()) ++ xwc->width = workArea.width () - (window->border ().left + window->border ().right); ++ ++ if (xwc->height > workArea.height ()) ++ xwc->height = workArea.height () - (window->border ().top + window->border ().bottom); ++ ++ } ++ ++ window->priv->moved = false; ++ } + /* constrain window width if smaller than minimum width */ + if (!(mask & CWWidth) && (int) old.width () < sizeHints.min_width) + { +@@ -6581,6 +6606,8 @@ + lastPong (0), + alive (true), + ++ moved (false), ++ + struts (0), + + icons (0), +@@ -6728,6 +6755,12 @@ + return priv->alive; + } + ++bool ++CompWindow::moved () const ++{ ++ return priv->moved; ++} ++ + unsigned int + CompWindow::mwmDecor () + { diff -Nru compiz-0.9.7.12/debian/patches/series compiz-0.9.7.12/debian/patches/series --- compiz-0.9.7.12/debian/patches/series 2013-09-23 09:15:09.000000000 -0400 +++ compiz-0.9.7.12/debian/patches/series 2014-07-07 14:57:39.000000000 -0400 @@ -4,3 +4,4 @@ force_unredirect_enabling.patch blacklist_precise_mesa80_intel_nouveau.patch fix_1095001.patch +fix_external_monitor_hotplug.patch