Previously, compiz erased its record of a window's parent frames when
it got the DestroyNotify for that window, which could leave it with no
way to process a stacking update relative to that frame window.
Instead, when unparenting a window, set a StructureNotify on the frame
and leave priv->frame set until the DestroyNotify comes back.
The approximate race is:
* compiz receives ConfigureRequest(w=A, {sibling=B, stack=Above})
* compiz calls XConfigureWindow(w=A's-frame, {sibling=B's frame,
stack=Above})
* compiz receives DestroyNotify(w=B)
* compiz calls XDestroyWindow(w=B's frame)
* compiz unsets w->priv->frame
* compiz receives ConfigureNotify(w=A's frame, {sibling=B's frame,
stack=Above})
* compiz is unable to process ConfigureNotify, because no window has
priv->id == B's frame || priv->frame == B's frame
This may have issues since priv->frame will be set and priv->destroyed
will be false when priv->id is 0 and the window itself has been
destroyed, but in casual usage I haven't run into any of them
Signed-off-by: Evan Broder <[email protected]>
---
src/event.cpp | 11 +++++++++++
src/window.cpp | 45 ++++++++++++++++++++++++++-------------------
2 files changed, 37 insertions(+), 19 deletions(-)
diff --git a/src/event.cpp b/src/event.cpp
index c79cd2b..05ee4e8 100644
--- a/src/event.cpp
+++ b/src/event.cpp
@@ -1104,6 +1104,17 @@ CompScreen::handleEvent (XEvent *event)
w->moveInputFocusToOtherWindow ();
w->destroy ();
}
+ else
+ {
+ w = findTopLevelWindow (event->xdestroywindow.window);
+ if (w && event->xdestroywindow.window == w->frame())
+ {
+ w->priv->frame = None;
+ if (w->priv->id == 1)
+ w->destroy();
+ }
+ }
+
break;
case MapNotify:
diff --git a/src/window.cpp b/src/window.cpp
index ee77619..026ec20 100644
--- a/src/window.cpp
+++ b/src/window.cpp
@@ -1203,20 +1203,22 @@ CompWindow::destroy ()
priv->id = 1;
priv->mapNum = 0;
+ if (priv->frame)
+ {
+ priv->unreparent ();
+ return;
+ }
+
priv->destroyRefCnt--;
if (priv->destroyRefCnt)
return;
-
if (!priv->destroyed)
{
priv->destroyed = true;
screen->priv->pendingDestroys++;
}
- if (priv->frame)
- priv->unreparent ();
-
}
void
@@ -1667,23 +1669,26 @@ PrivateWindow::configureFrame (XConfigureEvent *ce)
if (!priv->frame)
return;
- x = ce->x + priv->input.left;
- y = ce->y + priv->input.top;
- width = ce->width - priv->serverGeometry.border () * 2 - priv->input.left
- priv->input.right;
- height = ce->height - priv->serverGeometry.border () * 2 - priv->input.top
- priv->input.bottom;
-
- if (priv->syncWait)
- {
- priv->syncGeometry.set (x, y, width, height, ce->border_width);
- }
- else
+ if (priv->id != 1)
{
- if (ce->override_redirect)
+ x = ce->x + priv->input.left;
+ y = ce->y + priv->input.top;
+ width = ce->width - priv->serverGeometry.border () * 2 -
priv->input.left - priv->input.right;
+ height = ce->height - priv->serverGeometry.border () * 2 -
priv->input.top - priv->input.bottom;
+
+ if (priv->syncWait)
{
- priv->serverGeometry.set (x, y, width, height, ce->border_width);
+ priv->syncGeometry.set (x, y, width, height, ce->border_width);
}
+ else
+ {
+ if (ce->override_redirect)
+ {
+ priv->serverGeometry.set (x, y, width, height,
ce->border_width);
+ }
- window->resize (x, y, width, height, ce->border_width);
+ window->resize (x, y, width, height, ce->border_width);
+ }
}
if (priv->restack (ce->above))
@@ -6068,9 +6073,11 @@ PrivateWindow::unreparent ()
XFree (children);
XDestroyWindow (dpy, wrapper);
- XDestroyWindow (dpy, frame);
wrapper = None;
- frame = None;
+
+ /* We want to know when the frame is actually destroyed */
+ XSelectInput (dpy, frame, StructureNotifyMask);
+ XDestroyWindow (dpy, frame);
window->windowNotify (CompWindowNotifyUnreparent);
}
--
1.7.4.3
_______________________________________________
dev mailing list
[email protected]
http://lists.compiz.org/mailman/listinfo/dev