Merge lp:~compiz-team/compiz-core/compiz-core.fix_864330 into lp:compiz-core/0.9.5

Proposed by Sam Spilsbury
Status: Merged
Merged at revision: 2877
Proposed branch: lp:~compiz-team/compiz-core/compiz-core.fix_864330
Merge into: lp:compiz-core/0.9.5
Diff against target: 563 lines (+198/-74)
4 files modified
plugins/move/src/move.cpp (+1/-1)
src/privatescreen.h (+6/-0)
src/privatewindow.h (+2/-1)
src/window.cpp (+189/-72)
To merge this branch: bzr merge lp:~compiz-team/compiz-core/compiz-core.fix_864330
Reviewer Review Type Date Requested Status
Jason Smith (community) Approve
Review via email: mp+78935@code.launchpad.net

Description of the change

Rework the event tracking system slightly to cover more cases where events would
not be recorded properly:

1. When determining restack requests relative to another window which is pending
   a restack, check to see if we already requested to restack relative to it
   after it was pending the restack, rather than unconditionally submitting
   the restack and risking that being a no-op
2. When a window gets closed, its frame window is marked "None" immediately
   so we must discard tracking of any remaining pending configure events
   as they wont come to the frame window as we know it
3. Remove the static timeout and replace it with a timer object that clears up
   any stale configure requests which didn't get matched to events (note that
   this will be removed, but exists only to safeguard against performance regressions
   with the current API)
4. Make the move plugin lock down server geometry updates whenever it receives the
   "lock_position" signal on either the frame or the client window
5. Fix a problem with maximizing undecorated windows (resized to height = 0)

To post a comment you must log in.
Revision history for this message
Jason Smith (jassmith) wrote :

code looks good, testing hasn't yet revealed any issues

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'plugins/move/src/move.cpp'
2--- plugins/move/src/move.cpp 2011-09-29 03:29:41 +0000
3+++ plugins/move/src/move.cpp 2011-10-11 09:53:25 +0000
4@@ -525,7 +525,7 @@
5 Window xid = CompOption::getIntOptionNamed (options, "window", 0);
6 int lock = CompOption::getIntOptionNamed (options, "active", 0);
7
8- if (xid == w->id ())
9+ if (xid == ROOTPARENT (w))
10 MoveWindow::get (w)->mLocked = lock ? true : false;
11 }
12 }
13
14=== modified file 'src/privatescreen.h'
15--- src/privatescreen.h 2011-10-04 11:28:15 +0000
16+++ src/privatescreen.h 2011-10-11 09:53:25 +0000
17@@ -111,6 +111,8 @@
18 virtual ~PendingEvent ();
19
20 virtual bool match (XEvent *);
21+ unsigned int serial () { return mSerial; } // HACK: will be removed
22+ virtual void dump ();
23
24 typedef boost::shared_ptr<PendingEvent> Ptr;
25
26@@ -131,6 +133,8 @@
27
28 virtual bool match (XEvent *);
29 bool matchVM (unsigned int valueMask);
30+ bool matchRequest (XWindowChanges &xwc, unsigned int);
31+ virtual void dump ();
32
33 typedef boost::shared_ptr<PendingConfigureEvent> Ptr;
34
35@@ -154,6 +158,8 @@
36 bool match (XEvent *);
37 bool pending ();
38 bool forEachIf (boost::function <bool (compiz::X11::PendingEvent::Ptr)>);
39+ void clear () { mEvents.clear (); } // HACK will be removed
40+ void dump ();
41
42 protected:
43 bool removeIfMatching (const PendingEvent::Ptr &p, XEvent *);
44
45=== modified file 'src/privatewindow.h'
46--- src/privatewindow.h 2011-10-04 11:28:15 +0000
47+++ src/privatewindow.h 2011-10-11 09:53:25 +0000
48@@ -211,7 +211,7 @@
49
50 void readIconHint ();
51
52- void addPendingConfigure (XWindowChanges &, unsigned int);
53+ bool checkClear ();
54
55 public:
56
57@@ -293,6 +293,7 @@
58 typedef std::pair <XWindowChanges, unsigned int> XWCValueMask;
59
60 compiz::X11::PendingEventQueue pendingConfigures;
61+ CompTimer mClearCheckTimeout;
62 bool pendingPositionUpdates;
63
64 char *startupId;
65
66=== modified file 'src/window.cpp'
67--- src/window.cpp 2011-10-08 11:38:21 +0000
68+++ src/window.cpp 2011-10-11 09:53:25 +0000
69@@ -897,13 +897,16 @@
70
71 }
72
73- gettimeofday (&lastConfigureRequest, NULL);
74 compiz::X11::PendingEvent::Ptr pc =
75 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
76 new compiz::X11::PendingConfigureEvent (
77 screen->dpy (), serverFrame, valueMask, &xwc)));
78
79 pendingConfigures.add (pc);
80+ if (priv->mClearCheckTimeout.active ())
81+ priv->mClearCheckTimeout.stop ();
82+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
83+ 2000, 2500);
84
85 XSendEvent (screen->dpy (), screen->root (), false,
86 SubstructureNotifyMask, (XEvent *) &xev);
87@@ -913,13 +916,16 @@
88 }
89 else
90 {
91- gettimeofday (&lastConfigureRequest, NULL);
92 compiz::X11::PendingEvent::Ptr pc =
93 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
94 new compiz::X11::PendingConfigureEvent (
95 screen->dpy (), serverFrame, valueMask, &xwc)));
96
97 pendingConfigures.add (pc);
98+ if (priv->mClearCheckTimeout.active ())
99+ priv->mClearCheckTimeout.stop ();
100+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
101+ 2000, 2500);
102 XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
103 }
104
105@@ -951,10 +957,7 @@
106 if (shaded)
107 xwc.height = bw;
108 else
109- xwc.height = bw;
110-
111- if (shaded)
112- height = 0;
113+ xwc.height = serverGeometry.height () + bw;
114
115 if (serverFrameGeometry.x () == xwc.x)
116 valueMask &= ~(CWX);
117@@ -1032,13 +1035,16 @@
118
119 }
120
121- gettimeofday (&lastConfigureRequest, NULL);
122 compiz::X11::PendingEvent::Ptr pc =
123 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
124 new compiz::X11::PendingConfigureEvent (
125 screen->dpy (), serverFrame, valueMask, &xwc)));
126
127 pendingConfigures.add (pc);
128+ if (priv->mClearCheckTimeout.active ())
129+ priv->mClearCheckTimeout.stop ();
130+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
131+ 2000, 2500);
132
133 XSendEvent (screen->dpy (), screen->root (), false,
134 SubstructureNotifyMask, (XEvent *) &xev);
135@@ -1048,13 +1054,16 @@
136 }
137 else
138 {
139- gettimeofday (&lastConfigureRequest, NULL);
140 compiz::X11::PendingEvent::Ptr pc =
141 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
142 new compiz::X11::PendingConfigureEvent (
143 screen->dpy (), serverFrame, valueMask, &xwc)));
144
145 pendingConfigures.add (pc);
146+ if (priv->mClearCheckTimeout.active ())
147+ priv->mClearCheckTimeout.stop ();
148+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
149+ 2000, 2500);
150
151 XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc);
152 }
153@@ -2088,7 +2097,7 @@
154 #ifdef DEBUG
155 abort ();
156 #else
157- pendingConfigures = compiz::X11::PendingEventQueue (screen->dpy ());
158+ pendingConfigures.clear ();
159 #endif
160 }
161
162@@ -2199,28 +2208,13 @@
163 {
164 XWindowChanges xwc;
165 unsigned int valueMask = CWX | CWY;
166- struct timeval tv, old;
167- compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\
168+ compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x, "\
169 "moving window asyncrhonously!", (unsigned int) priv->serverId);
170
171- old = priv->lastConfigureRequest;
172- gettimeofday (&tv, NULL);
173-
174 xwc.x = priv->serverGeometry.x () + dx;
175 xwc.y = priv->serverGeometry.y () + dy;
176
177 configureXWindow (valueMask, &xwc);
178-
179- priv->lastConfigureRequest = old;
180-
181- /* FIXME: This is a hack to avoid performance regressions
182- * and must be removed in 0.9.6 */
183- if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 30000)
184- {
185- compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n",
186- priv->lastConfigureRequest.tv_usec, tv.tv_usec);
187- priv->pendingConfigures = compiz::X11::PendingEventQueue (screen->dpy ());
188- }
189 }
190 }
191 }
192@@ -2231,16 +2225,59 @@
193 return !mEvents.empty ();
194 }
195
196+bool
197+PrivateWindow::checkClear ()
198+{
199+ if (pendingConfigures.pending ())
200+ {
201+ /* FIXME: This is a hack to avoid performance regressions
202+ * and must be removed in 0.9.6 */
203+ compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event on 0x%x\n",
204+ id);
205+ pendingConfigures.dump ();
206+ pendingConfigures.clear ();
207+ }
208+
209+ return false;
210+}
211+
212 void
213 compiz::X11::PendingEventQueue::add (PendingEvent::Ptr p)
214 {
215+ compLogMessage ("core", CompLogLevelDebug, "pending request:");
216+ p->dump ();
217+
218 mEvents.push_back (p);
219 }
220
221 bool
222 compiz::X11::PendingEventQueue::removeIfMatching (const PendingEvent::Ptr &p, XEvent *event)
223 {
224- return p->match (event);
225+ if (p->match (event))
226+ {
227+ compLogMessage ("core", CompLogLevelDebug, "received event:");
228+ p->dump ();
229+ return true;
230+ }
231+
232+ return false;
233+}
234+
235+void
236+compiz::X11::PendingEvent::dump ()
237+{
238+ compLogMessage ("core", CompLogLevelDebug, "- event serial: %i", mSerial);
239+ compLogMessage ("core", CompLogLevelDebug, "- event window 0x%x", mWindow);
240+}
241+
242+void
243+compiz::X11::PendingConfigureEvent::dump ()
244+{
245+ compiz::X11::PendingEvent::dump ();
246+
247+ compLogMessage ("core", CompLogLevelDebug, "- x: %i y: %i width: %i height: %i "\
248+ "border: %i, sibling: 0x%x",
249+ mXwc.x, mXwc.y, mXwc.width, mXwc.height, mXwc.border_width, mXwc.sibling);
250 }
251
252 bool
253@@ -2266,8 +2303,21 @@
254 return false;
255 }
256
257+void
258+compiz::X11::PendingEventQueue::dump ()
259+{
260+ foreach (compiz::X11::PendingEvent::Ptr p, mEvents)
261+ p->dump ();
262+}
263+
264 compiz::X11::PendingEventQueue::PendingEventQueue (Display *d)
265 {
266+ /* mClearCheckTimeout.setTimes (0, 0)
267+ *
268+ * XXX: For whatever reason, calling setTimes (0, 0) here causes
269+ * the destructor of the timer object to be called twice later on
270+ * in execution and the stack gets smashed. This could be a
271+ * compiler bug, but requires further investigation */
272 }
273
274 compiz::X11::PendingEventQueue::~PendingEventQueue ()
275@@ -2310,7 +2360,44 @@
276 bool
277 compiz::X11::PendingConfigureEvent::matchVM (unsigned int valueMask)
278 {
279- return valueMask & mValueMask;
280+ unsigned int result = mValueMask != 0 ? valueMask & mValueMask : 1;
281+
282+ return result != 0;
283+}
284+
285+bool
286+compiz::X11::PendingConfigureEvent::matchRequest (XWindowChanges &xwc, unsigned int valueMask)
287+{
288+ if (matchVM (valueMask))
289+ {
290+ if (valueMask & CWX)
291+ if (xwc.x != mXwc.x)
292+ return false;
293+
294+ if (valueMask & CWY)
295+ if (xwc.y != mXwc.y)
296+ return false;
297+
298+ if (valueMask & CWWidth)
299+ if (xwc.width != mXwc.width)
300+ return false;
301+
302+ if (valueMask & CWHeight)
303+ if (xwc.height != mXwc.height)
304+ return false;
305+
306+ if (valueMask & CWBorderWidth)
307+ if (xwc.border_width != mXwc.border_width)
308+ return false;
309+
310+ if (valueMask & (CWStackMode | CWSibling))
311+ if (xwc.sibling != mXwc.sibling)
312+ return false;
313+
314+ return true;
315+ }
316+
317+ return false;
318 }
319
320 bool
321@@ -2322,29 +2409,16 @@
322 if (!compiz::X11::PendingEvent::match (event))
323 return false;
324
325- if (mValueMask & CWX)
326- if (ce->x != mXwc.x)
327- matched = false;
328-
329- if (mValueMask & CWY)
330- if (ce->y != mXwc.y)
331- matched = false;
332-
333- if (mValueMask & CWWidth)
334- if (ce->width != mXwc.width)
335- matched = false;
336-
337- if (mValueMask & CWHeight)
338- if (ce->height != mXwc.height)
339- matched = false;
340-
341- if (mValueMask & CWBorderWidth)
342- if (ce->border_width != mXwc.border_width)
343- matched = false;
344-
345- if (mValueMask & (CWStackMode | CWSibling))
346- if (ce->above != mXwc.sibling)
347- matched = false;
348+ XWindowChanges xwc;
349+
350+ xwc.x = ce->x;
351+ xwc.y = ce->y;
352+ xwc.width = ce->width;
353+ xwc.height = ce->height;
354+ xwc.border_width = ce->border_width;
355+ xwc.sibling = ce->above;
356+
357+ matched = matchRequest (xwc, mValueMask);
358
359 /* Remove events from the queue
360 * even if they didn't match what
361@@ -2440,7 +2514,6 @@
362 xwc.x = priv->serverFrameGeometry.x ();
363 xwc.y = priv->serverFrameGeometry.y ();
364
365- gettimeofday (&priv->lastConfigureRequest, NULL);
366 compiz::X11::PendingEvent::Ptr pc =
367 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
368 new compiz::X11::PendingConfigureEvent (
369@@ -2448,6 +2521,11 @@
370
371 priv->pendingConfigures.add (pc);
372
373+ /* Got 3 seconds to get its stuff together */
374+ if (priv->mClearCheckTimeout.active ())
375+ priv->mClearCheckTimeout.stop ();
376+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
377+ 2000, 2500);
378 XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc);
379
380 if (priv->serverFrame)
381@@ -3259,11 +3337,18 @@
382 return pc->matchVM (CWStackMode | CWSibling);
383 }
384
385+static bool isExistingRequest (compiz::X11::PendingEvent::Ptr p, XWindowChanges &xwc, unsigned int valueMask)
386+{
387+ compiz::X11::PendingConfigureEvent::Ptr pc = boost::shared_static_cast <compiz::X11::PendingConfigureEvent> (p);
388+
389+ return pc->matchRequest (xwc, valueMask);
390+}
391+
392 void
393 PrivateWindow::reconfigureXWindow (unsigned int valueMask,
394 XWindowChanges *xwc)
395 {
396- unsigned int frameValueMask = valueMask;
397+ unsigned int frameValueMask = 0;
398
399 /* Immediately sync window position
400 * if plugins were updating w->geometry () directly
401@@ -3273,28 +3358,37 @@
402
403 /* Remove redundant bits */
404
405- if (serverGeometry.x () == xwc->x)
406+ if (valueMask & CWX && serverGeometry.x () == xwc->x)
407 valueMask &= ~(CWX);
408
409- if (serverGeometry.y () == xwc->y)
410+ if (valueMask & CWY && serverGeometry.y () == xwc->y)
411 valueMask &= ~(CWY);
412
413- if (serverGeometry.width () == xwc->width)
414+ if (valueMask & CWWidth && serverGeometry.width () == xwc->width)
415 valueMask &= ~(CWWidth);
416
417- if (serverGeometry.height () == xwc->height)
418+ if (valueMask & CWHeight && serverGeometry.height () == xwc->height)
419 valueMask &= ~(CWHeight);
420
421- if (serverGeometry.border () == xwc->border_width)
422+ if (valueMask & CWBorderWidth && serverGeometry.border () == xwc->border_width)
423 valueMask &= ~(CWBorderWidth);
424
425- if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling)
426+ if (valueMask & CWSibling && window->serverPrev)
427 {
428 /* check if the sibling is also pending a restack,
429 * if not, then setting this bit is useless */
430-
431- if (window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1)))
432- valueMask &= ~(CWSibling | CWStackMode);
433+ if (ROOTPARENT (window->serverPrev) == xwc->sibling)
434+ {
435+ bool matchingRequest = priv->pendingConfigures.forEachIf (boost::bind (isExistingRequest, _1, *xwc, valueMask));
436+ bool restackPending = window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1));
437+ bool remove = matchingRequest;
438+
439+ if (!remove)
440+ remove = !restackPending;
441+
442+ if (remove)
443+ valueMask &= ~(CWSibling | CWStackMode);
444+ }
445 }
446
447 if (valueMask & CWBorderWidth)
448@@ -3330,13 +3424,18 @@
449 compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above");
450 }
451
452- if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
453+ frameValueMask = valueMask;
454+
455+ if (frameValueMask & CWX &&
456+ serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left)
457 frameValueMask &= ~(CWX);
458
459- if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
460+ if (frameValueMask & CWY &&
461+ serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top)
462 frameValueMask &= ~(CWY);
463
464- if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
465+ if (frameValueMask & CWWidth &&
466+ serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2
467 + serverInput.left + serverInput.right)
468 frameValueMask &= ~(CWWidth);
469
470@@ -3346,13 +3445,15 @@
471
472 if (shaded)
473 {
474- if (serverFrameGeometry.height () == serverGeometry.border () * 2
475+ if (frameValueMask & CWHeight &&
476+ serverFrameGeometry.height () == serverGeometry.border () * 2
477 + serverInput.top + serverInput.bottom)
478 frameValueMask &= ~(CWHeight);
479 }
480 else
481 {
482- if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
483+ if (frameValueMask & CWHeight &&
484+ serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2
485 + serverInput.top + serverInput.bottom)
486 frameValueMask &= ~(CWHeight);
487 }
488@@ -3397,14 +3498,16 @@
489 wc.width = serverFrameGeometry.width ();
490 wc.height = serverFrameGeometry.height ();
491
492- gettimeofday (&lastConfigureRequest, NULL);
493-
494 compiz::X11::PendingEvent::Ptr pc =
495 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
496 new compiz::X11::PendingConfigureEvent (
497 screen->dpy (), priv->serverFrame, frameValueMask, &wc)));
498
499 pendingConfigures.add (pc);
500+ if (priv->mClearCheckTimeout.active ())
501+ priv->mClearCheckTimeout.stop ();
502+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
503+ 2000, 2500);
504
505 XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc);
506 }
507@@ -4196,13 +4299,16 @@
508
509 if (serverFrame)
510 {
511- gettimeofday (&lastConfigureRequest, NULL);
512 compiz::X11::PendingEvent::Ptr pc =
513 boost::shared_static_cast<compiz::X11::PendingEvent> (compiz::X11::PendingConfigureEvent::Ptr (
514 new compiz::X11::PendingConfigureEvent (
515 screen->dpy (), serverFrame, valueMask, &lxwc)));
516
517 pendingConfigures.add (pc);
518+ if (priv->mClearCheckTimeout.active ())
519+ priv->mClearCheckTimeout.stop ();
520+ priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv),
521+ 2000, 2500);
522 }
523
524 /* Below with no sibling puts the window at the bottom
525@@ -4215,8 +4321,15 @@
526 }
527 else if (sibling)
528 {
529+ bool matchingRequest = priv->pendingConfigures.forEachIf (boost::bind (isExistingRequest, _1, *xwc, (CWStackMode | CWSibling)));
530+ bool restackPending = window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1));
531+ bool processAnyways = restackPending;
532+
533+ if (matchingRequest)
534+ processAnyways = false;
535+
536 if (sibling->priv->id != window->serverPrev->priv->id ||
537- window->serverPrev->priv->pendingConfigures.forEachIf (boost::bind (isPendingRestack, _1)))
538+ processAnyways)
539 {
540 mask |= CWSibling | CWStackMode;
541
542@@ -6295,8 +6408,6 @@
543 if (dbg)
544 dbg->overrideRedirectRestack (priv->id, aboveId);
545
546- gettimeofday (&priv->lastConfigureRequest, NULL);
547-
548 priv->attrib = wa;
549 priv->serverGeometry.set (priv->attrib.x, priv->attrib.y,
550 priv->attrib.width, priv->attrib.height,
551@@ -7229,6 +7340,12 @@
552 XDestroyWindow (screen->dpy (), wrapper);
553
554 window->windowNotify (CompWindowNotifyUnreparent);
555+ /* This window is no longer "managed" in the
556+ * reparenting sense so clear its pending event
557+ * queue ... though maybe in future it would
558+ * be better to bookeep these events too and
559+ * handle the ReparentNotify */
560+ pendingConfigures.clear ();
561
562 frame = None;
563 wrapper = None;

Subscribers

People subscribed via source and target branches