Merge lp:~compiz-team/compiz/compiz.fix_1171314 into lp:compiz/0.9.10
- compiz.fix_1171314
- Merge into 0.9.10
Status: | Merged |
---|---|
Approved by: | Sam Spilsbury |
Approved revision: | 3748 |
Merged at revision: | 3763 |
Proposed branch: | lp:~compiz-team/compiz/compiz.fix_1171314 |
Merge into: | lp:compiz/0.9.10 |
Diff against target: |
771 lines (+542/-71) 10 files modified
src/privatewindow.h (+1/-0) src/window.cpp (+40/-54) tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp (+1/-15) tests/system/xorg-gtest/tests/compiz_xorg_gtest_test_window_stacking.cpp (+403/-0) tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp (+5/-1) tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h (+2/-0) tests/xorg-gtest/include/compiz-xorg-gtest.h (+2/-0) tests/xorg-gtest/plugins/testhelper/src/testhelper.cpp (+61/-1) tests/xorg-gtest/plugins/testhelper/src/testhelper.h (+6/-0) tests/xorg-gtest/src/compiz-xorg-gtest.cpp (+21/-0) |
To merge this branch: | bzr merge lp:~compiz-team/compiz/compiz.fix_1171314 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
MC Return | Approve | ||
Review via email: mp+171669@code.launchpad.net |
This proposal supersedes a proposal from 2013-06-26.
Commit message
Don't add the frame to the toplevel stack if it hasn't been created yet.
In the event that a window is unreparented or destroyed, we usually need
to add its frame window to the toplevel window stack until the time at
which we recieve a DestroyNotify for it, as there may be incoming
ConfigureNotify events puporting to stack other windows relative to
that frame.
However, this does not apply in the case where we have not yet received
a CreateNotify for the frame window. In that case, it is not possible
for any stacking requests to be made relative to this window, so it
does not need to be added immediately. Instead, we can add it at the
time that we recieve a CreateNotify for it as a regular override
redirect window until the time that it is later destroyed.
(LP: #1171314)
Description of the change
Don't add the frame to the toplevel stack if it hasn't been created yet.
In the event that a window is unreparented or destroyed, we usually need
to add its frame window to the toplevel window stack until the time at
which we recieve a DestroyNotify for it, as there may be incoming
ConfigureNotify events puporting to stack other windows relative to
that frame.
However, this does not apply in the case where we have not yet received
a CreateNotify for the frame window. In that case, it is not possible
for any stacking requests to be made relative to this window, so it
does not need to be added immediately. Instead, we can add it at the
time that we recieve a CreateNotify for it as a regular override
redirect window until the time that it is later destroyed.
(LP: #1171314)
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
PS Jenkins bot (ps-jenkins) wrote : Posted in a previous version of this proposal | # |
FAILED: Continuous integration, rev:3748
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:3748
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
MC Return (mc-return) wrote : | # |
LGTM, AFAICT. +1
I have not tested it though...
MC Return (mc-return) wrote : | # |
Can anyone help with testing this ?
PS Jenkins bot (ps-jenkins) : | # |
Preview Diff
1 | === modified file 'src/privatewindow.h' | |||
2 | --- src/privatewindow.h 2013-03-06 12:31:24 +0000 | |||
3 | +++ src/privatewindow.h 2013-06-26 21:25:34 +0000 | |||
4 | @@ -252,6 +252,7 @@ | |||
5 | 252 | 252 | ||
6 | 253 | bool reparent (); | 253 | bool reparent (); |
7 | 254 | void unreparent (); | 254 | void unreparent (); |
8 | 255 | void manageFrameWindowSeparately (); | ||
9 | 255 | 256 | ||
10 | 256 | void hide (); | 257 | void hide (); |
11 | 257 | 258 | ||
12 | 258 | 259 | ||
13 | === modified file 'src/window.cpp' | |||
14 | --- src/window.cpp 2013-05-27 16:19:59 +0000 | |||
15 | +++ src/window.cpp 2013-06-26 21:25:34 +0000 | |||
16 | @@ -1189,33 +1189,7 @@ | |||
17 | 1189 | CompWindow *oldNext = next; | 1189 | CompWindow *oldNext = next; |
18 | 1190 | CompWindow *oldPrev = prev; | 1190 | CompWindow *oldPrev = prev; |
19 | 1191 | 1191 | ||
47 | 1192 | /* This is where things get tricky ... it is possible | 1192 | priv->manageFrameWindowSeparately (); |
21 | 1193 | * to receive a ConfigureNotify relative to a frame window | ||
22 | 1194 | * for a destroyed window in case we process a ConfigureRequest | ||
23 | 1195 | * for the destroyed window and then a DestroyNotify for it directly | ||
24 | 1196 | * afterwards. In that case, we will receive the ConfigureNotify | ||
25 | 1197 | * for the XConfigureWindow request we made relative to that frame | ||
26 | 1198 | * window. Because of this, we must keep the frame window in the stack | ||
27 | 1199 | * as a new toplevel window so that the ConfigureNotify will be processed | ||
28 | 1200 | * properly until it too receives a DestroyNotify */ | ||
29 | 1201 | |||
30 | 1202 | if (priv->serverFrame) | ||
31 | 1203 | { | ||
32 | 1204 | XWindowAttributes attrib; | ||
33 | 1205 | |||
34 | 1206 | /* It's possible that the frame window was already destroyed because | ||
35 | 1207 | * the client was unreparented before it was destroyed (eg | ||
36 | 1208 | * UnmapNotify before DestroyNotify). In that case the frame window | ||
37 | 1209 | * is going to be an invalid window but since we haven't received | ||
38 | 1210 | * a DestroyNotify for it yet, it is possible that restacking | ||
39 | 1211 | * operations could occurr relative to it so we need to hold it | ||
40 | 1212 | * in the stack for now. Ensure that it is marked override redirect */ | ||
41 | 1213 | XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib); | ||
42 | 1214 | |||
43 | 1215 | /* Put the frame window "above" the client window | ||
44 | 1216 | * in the stack */ | ||
45 | 1217 | PrivateWindow::createCompWindow (priv->id, priv->id, attrib, priv->serverFrame); | ||
46 | 1218 | } | ||
48 | 1219 | 1193 | ||
49 | 1220 | /* Immediately unhook the window once destroyed | 1194 | /* Immediately unhook the window once destroyed |
50 | 1221 | * as the stacking order will be invalid if we don't | 1195 | * as the stacking order will be invalid if we don't |
51 | @@ -6867,6 +6841,44 @@ | |||
52 | 6867 | } | 6841 | } |
53 | 6868 | 6842 | ||
54 | 6869 | void | 6843 | void |
55 | 6844 | PrivateWindow::manageFrameWindowSeparately () | ||
56 | 6845 | { | ||
57 | 6846 | /* This is where things get tricky ... it is possible | ||
58 | 6847 | * to receive a ConfigureNotify relative to a frame window | ||
59 | 6848 | * for a destroyed window in case we process a ConfigureRequest | ||
60 | 6849 | * for the destroyed window and then a DestroyNotify for it directly | ||
61 | 6850 | * afterwards. In that case, we will receive the ConfigureNotify | ||
62 | 6851 | * for the XConfigureWindow request we made relative to that frame | ||
63 | 6852 | * window. Because of this, we must keep the frame window in the stack | ||
64 | 6853 | * as a new toplevel window so that the ConfigureNotify will be processed | ||
65 | 6854 | * properly until it too receives a DestroyNotify | ||
66 | 6855 | * | ||
67 | 6856 | * We only wish to do this if we have recieved a CreateNotify for the | ||
68 | 6857 | * frame window. If we have not, then there will be no stacking operations | ||
69 | 6858 | * dependent on it and we should wait until CreateNotify in order to manage | ||
70 | 6859 | * it normally */ | ||
71 | 6860 | |||
72 | 6861 | if (frame) | ||
73 | 6862 | { | ||
74 | 6863 | XWindowAttributes attrib; | ||
75 | 6864 | |||
76 | 6865 | /* It's possible that the frame window was already destroyed because | ||
77 | 6866 | * the client was unreparented before it was destroyed (eg | ||
78 | 6867 | * UnmapNotify before DestroyNotify). In that case the frame window | ||
79 | 6868 | * is going to be an invalid window but since we haven't received | ||
80 | 6869 | * a DestroyNotify for it yet, it is possible that restacking | ||
81 | 6870 | * operations could occurr relative to it so we need to hold it | ||
82 | 6871 | * in the stack for now. Ensure that it is marked override redirect */ | ||
83 | 6872 | window->priv->queryFrameAttributes (attrib); | ||
84 | 6873 | |||
85 | 6874 | /* Put the frame window "above" the client window | ||
86 | 6875 | * in the stack */ | ||
87 | 6876 | PrivateWindow::createCompWindow (id, id, attrib, frame); | ||
88 | 6877 | } | ||
89 | 6878 | |||
90 | 6879 | } | ||
91 | 6880 | |||
92 | 6881 | void | ||
93 | 6870 | PrivateWindow::unreparent () | 6882 | PrivateWindow::unreparent () |
94 | 6871 | { | 6883 | { |
95 | 6872 | if (!serverFrame) | 6884 | if (!serverFrame) |
96 | @@ -6961,33 +6973,7 @@ | |||
97 | 6961 | if (dbg) | 6973 | if (dbg) |
98 | 6962 | dbg->addDestroyedFrame (serverFrame); | 6974 | dbg->addDestroyedFrame (serverFrame); |
99 | 6963 | 6975 | ||
127 | 6964 | /* This is where things get tricky ... it is possible | 6976 | manageFrameWindowSeparately (); |
101 | 6965 | * to receive a ConfigureNotify relative to a frame window | ||
102 | 6966 | * for a destroyed window in case we process a ConfigureRequest | ||
103 | 6967 | * for the destroyed window and then a DestroyNotify for it directly | ||
104 | 6968 | * afterwards. In that case, we will receive the ConfigureNotify | ||
105 | 6969 | * for the XConfigureWindow request we made relative to that frame | ||
106 | 6970 | * window. Because of this, we must keep the frame window in the stack | ||
107 | 6971 | * as a new toplevel window so that the ConfigureNotify will be processed | ||
108 | 6972 | * properly until it too receives a DestroyNotify */ | ||
109 | 6973 | |||
110 | 6974 | if (serverFrame) | ||
111 | 6975 | { | ||
112 | 6976 | XWindowAttributes attrib; | ||
113 | 6977 | |||
114 | 6978 | /* It's possible that the frame window was already destroyed because | ||
115 | 6979 | * the client was unreparented before it was destroyed (eg | ||
116 | 6980 | * UnmapNotify before DestroyNotify). In that case the frame window | ||
117 | 6981 | * is going to be an invalid window but since we haven't received | ||
118 | 6982 | * a DestroyNotify for it yet, it is possible that restacking | ||
119 | 6983 | * operations could occurr relative to it so we need to hold it | ||
120 | 6984 | * in the stack for now. Ensure that it is marked override redirect */ | ||
121 | 6985 | window->priv->queryFrameAttributes (attrib); | ||
122 | 6986 | |||
123 | 6987 | /* Put the frame window "above" the client window | ||
124 | 6988 | * in the stack */ | ||
125 | 6989 | PrivateWindow::createCompWindow (id, id, attrib, serverFrame); | ||
126 | 6990 | } | ||
128 | 6991 | 6977 | ||
129 | 6992 | /* Issue a DestroyNotify */ | 6978 | /* Issue a DestroyNotify */ |
130 | 6993 | XDestroyWindow (screen->dpy (), serverFrame); | 6979 | XDestroyWindow (screen->dpy (), serverFrame); |
131 | 6994 | 6980 | ||
132 | === modified file 'tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp' | |||
133 | --- tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp 2013-06-22 12:27:36 +0000 | |||
134 | +++ tests/system/xorg-gtest/tests/compiz_xorg_gtest_configure_window.cpp 2013-06-26 21:25:34 +0000 | |||
135 | @@ -59,21 +59,7 @@ | |||
136 | 59 | Window GetTopParent (Display *display, | 59 | Window GetTopParent (Display *display, |
137 | 60 | Window w) | 60 | Window w) |
138 | 61 | { | 61 | { |
154 | 62 | Window rootReturn = 0; | 62 | return ct::GetTopmostNonRootParent (display, w); |
140 | 63 | Window parentReturn = w; | ||
141 | 64 | Window lastParent = 0; | ||
142 | 65 | |||
143 | 66 | do | ||
144 | 67 | { | ||
145 | 68 | lastParent = parentReturn; | ||
146 | 69 | |||
147 | 70 | parentReturn = ct::GetImmediateParent (display, | ||
148 | 71 | lastParent, | ||
149 | 72 | rootReturn); | ||
150 | 73 | |||
151 | 74 | } while (parentReturn != rootReturn); | ||
152 | 75 | |||
153 | 76 | return lastParent; | ||
155 | 77 | } | 63 | } |
156 | 78 | 64 | ||
157 | 79 | bool QueryGeometry (Display *dpy, | 65 | bool QueryGeometry (Display *dpy, |
158 | 80 | 66 | ||
159 | === modified file 'tests/system/xorg-gtest/tests/compiz_xorg_gtest_test_window_stacking.cpp' | |||
160 | --- tests/system/xorg-gtest/tests/compiz_xorg_gtest_test_window_stacking.cpp 2013-02-26 11:56:10 +0000 | |||
161 | +++ tests/system/xorg-gtest/tests/compiz_xorg_gtest_test_window_stacking.cpp 2013-06-26 21:25:34 +0000 | |||
162 | @@ -25,8 +25,13 @@ | |||
163 | 25 | #include <stdexcept> | 25 | #include <stdexcept> |
164 | 26 | #include <gtest/gtest.h> | 26 | #include <gtest/gtest.h> |
165 | 27 | #include <gmock/gmock.h> | 27 | #include <gmock/gmock.h> |
166 | 28 | |||
167 | 29 | #include <boost/shared_array.hpp> | ||
168 | 30 | #include <boost/bind.hpp> | ||
169 | 31 | |||
170 | 28 | #include <xorg/gtest/xorg-gtest.h> | 32 | #include <xorg/gtest/xorg-gtest.h> |
171 | 29 | #include <compiz-xorg-gtest.h> | 33 | #include <compiz-xorg-gtest.h> |
172 | 34 | #include <compiz_xorg_gtest_communicator.h> | ||
173 | 30 | 35 | ||
174 | 31 | #include <X11/Xlib.h> | 36 | #include <X11/Xlib.h> |
175 | 32 | #include <X11/Xatom.h> | 37 | #include <X11/Xatom.h> |
176 | @@ -36,6 +41,7 @@ | |||
177 | 36 | using ::testing::Matcher; | 41 | using ::testing::Matcher; |
178 | 37 | 42 | ||
179 | 38 | namespace ct = compiz::testing; | 43 | namespace ct = compiz::testing; |
180 | 44 | namespace ctm = compiz::testing::messages; | ||
181 | 39 | 45 | ||
182 | 40 | class CompizXorgSystemStackingTest : | 46 | class CompizXorgSystemStackingTest : |
183 | 41 | public ct::AutostartCompizXorgSystemTest | 47 | public ct::AutostartCompizXorgSystemTest |
184 | @@ -429,3 +435,400 @@ | |||
185 | 429 | EXPECT_EQ (dock, (*it++)); | 435 | EXPECT_EQ (dock, (*it++)); |
186 | 430 | EXPECT_EQ (w1, (*it++)); | 436 | EXPECT_EQ (w1, (*it++)); |
187 | 431 | } | 437 | } |
188 | 438 | |||
189 | 439 | class StackingSync : | ||
190 | 440 | public ct::AutostartCompizXorgSystemTestWithTestHelper | ||
191 | 441 | { | ||
192 | 442 | public: | ||
193 | 443 | |||
194 | 444 | void SetUp (); | ||
195 | 445 | }; | ||
196 | 446 | |||
197 | 447 | void | ||
198 | 448 | StackingSync::SetUp () | ||
199 | 449 | { | ||
200 | 450 | ct::AutostartCompizXorgSystemTestWithTestHelper::SetUp (); | ||
201 | 451 | |||
202 | 452 | XSelectInput (Display (), DefaultRootWindow (Display ()), StructureNotifyMask | | ||
203 | 453 | SubstructureNotifyMask); | ||
204 | 454 | } | ||
205 | 455 | |||
206 | 456 | namespace | ||
207 | 457 | { | ||
208 | 458 | Window CreateAndWaitForCreation (Display *dpy) | ||
209 | 459 | { | ||
210 | 460 | Window w = ct::CreateNormalWindow (dpy); | ||
211 | 461 | Advance (dpy, | ||
212 | 462 | ct::WaitForEventOfTypeOnWindow (dpy, | ||
213 | 463 | DefaultRootWindow (dpy), | ||
214 | 464 | CreateNotify, | ||
215 | 465 | -1, | ||
216 | 466 | -1)); | ||
217 | 467 | return w; | ||
218 | 468 | } | ||
219 | 469 | |||
220 | 470 | Window CreateOverrideRedirectWindow (Display *dpy) | ||
221 | 471 | { | ||
222 | 472 | XSetWindowAttributes attrib; | ||
223 | 473 | |||
224 | 474 | attrib.override_redirect = true; | ||
225 | 475 | |||
226 | 476 | Window w = | ||
227 | 477 | XCreateWindow (dpy, DefaultRootWindow (dpy), | ||
228 | 478 | ct::WINDOW_X, | ||
229 | 479 | ct::WINDOW_Y, | ||
230 | 480 | ct::WINDOW_WIDTH, | ||
231 | 481 | ct::WINDOW_HEIGHT, | ||
232 | 482 | 0, | ||
233 | 483 | DefaultDepth (dpy, 0), | ||
234 | 484 | InputOutput, | ||
235 | 485 | DefaultVisual (dpy, DefaultScreen (dpy)), | ||
236 | 486 | CWOverrideRedirect, | ||
237 | 487 | &attrib); | ||
238 | 488 | |||
239 | 489 | XSelectInput (dpy, w, StructureNotifyMask); | ||
240 | 490 | return w; | ||
241 | 491 | } | ||
242 | 492 | |||
243 | 493 | Window MapAndWaitForParent (Display *dpy, Window w) | ||
244 | 494 | { | ||
245 | 495 | XMapRaised (dpy, w); | ||
246 | 496 | |||
247 | 497 | Advance (dpy, | ||
248 | 498 | ct::WaitForEventOfTypeOnWindow (dpy, | ||
249 | 499 | w, | ||
250 | 500 | ReparentNotify, | ||
251 | 501 | -1, | ||
252 | 502 | -1)); | ||
253 | 503 | |||
254 | 504 | return ct::GetTopmostNonRootParent (dpy, w); | ||
255 | 505 | } | ||
256 | 506 | |||
257 | 507 | void DestroyOnReparent (Display *dpy, | ||
258 | 508 | ct::MessageAtoms &atoms, | ||
259 | 509 | Window w) | ||
260 | 510 | { | ||
261 | 511 | Window root = DefaultRootWindow (dpy); | ||
262 | 512 | Atom atom = | ||
263 | 513 | atoms.FetchForString (ctm::TEST_HELPER_DESTROY_ON_REPARENT); | ||
264 | 514 | |||
265 | 515 | std::vector <long> data (4); | ||
266 | 516 | |||
267 | 517 | ct::SendClientMessage (dpy, atom, root, w, data); | ||
268 | 518 | } | ||
269 | 519 | |||
270 | 520 | Window WaitForNextCreatedWindow (Display *dpy) | ||
271 | 521 | { | ||
272 | 522 | XEvent ev; | ||
273 | 523 | while (true) | ||
274 | 524 | { | ||
275 | 525 | XNextEvent (dpy, &ev); | ||
276 | 526 | if (ev.type == CreateNotify) | ||
277 | 527 | return ev.xcreatewindow.window; | ||
278 | 528 | } | ||
279 | 529 | |||
280 | 530 | return 0; | ||
281 | 531 | } | ||
282 | 532 | |||
283 | 533 | void WaitForManage (Display *dpy, | ||
284 | 534 | ct::MessageAtoms &atoms) | ||
285 | 535 | { | ||
286 | 536 | Atom atom = | ||
287 | 537 | atoms.FetchForString (ctm::TEST_HELPER_WINDOW_READY); | ||
288 | 538 | XEvent ev; | ||
289 | 539 | |||
290 | 540 | ct::ReceiveMessage (dpy, atom, ev); | ||
291 | 541 | } | ||
292 | 542 | |||
293 | 543 | void RestackAbove (Display *dpy, | ||
294 | 544 | Window w, | ||
295 | 545 | Window above) | ||
296 | 546 | { | ||
297 | 547 | XWindowChanges xwc; | ||
298 | 548 | |||
299 | 549 | xwc.stack_mode = Above; | ||
300 | 550 | xwc.sibling = above; | ||
301 | 551 | |||
302 | 552 | XConfigureWindow (dpy, w, CWStackMode | CWSibling, &xwc); | ||
303 | 553 | } | ||
304 | 554 | |||
305 | 555 | void RestackAtLeastAbove (Display *dpy, | ||
306 | 556 | ct::MessageAtoms &atoms, | ||
307 | 557 | Window w, | ||
308 | 558 | Window above) | ||
309 | 559 | { | ||
310 | 560 | Window root = DefaultRootWindow (dpy); | ||
311 | 561 | Atom atom = | ||
312 | 562 | atoms.FetchForString (ctm::TEST_HELPER_RESTACK_ATLEAST_ABOVE); | ||
313 | 563 | |||
314 | 564 | std::vector <long> data (4); | ||
315 | 565 | |||
316 | 566 | data[0] = above; | ||
317 | 567 | ct::SendClientMessage (dpy, atom, root, w, data); | ||
318 | 568 | } | ||
319 | 569 | |||
320 | 570 | void FreeWindowArray (Window *array) | ||
321 | 571 | { | ||
322 | 572 | XFree (array); | ||
323 | 573 | } | ||
324 | 574 | |||
325 | 575 | typedef boost::shared_array <Window> WindowArray; | ||
326 | 576 | |||
327 | 577 | WindowArray GetChildren (Display *dpy, | ||
328 | 578 | Window w, | ||
329 | 579 | unsigned int &n) | ||
330 | 580 | { | ||
331 | 581 | Window unused; | ||
332 | 582 | Window *children; | ||
333 | 583 | |||
334 | 584 | if (!XQueryTree (dpy, w, &unused, &unused, &children, &n)) | ||
335 | 585 | throw std::logic_error ("XQueryTree failed"); | ||
336 | 586 | |||
337 | 587 | return WindowArray (children, boost::bind (FreeWindowArray, _1)); | ||
338 | 588 | } | ||
339 | 589 | |||
340 | 590 | class StackPositionMatcher : | ||
341 | 591 | public MatcherInterface <Window> | ||
342 | 592 | { | ||
343 | 593 | public: | ||
344 | 594 | |||
345 | 595 | StackPositionMatcher (const WindowArray &array, | ||
346 | 596 | Window cmp, | ||
347 | 597 | unsigned int n); | ||
348 | 598 | |||
349 | 599 | protected: | ||
350 | 600 | |||
351 | 601 | bool MatchAndExplain (Window window, | ||
352 | 602 | MatchResultListener *listener) const; | ||
353 | 603 | void DescribeTo (std::ostream *os) const; | ||
354 | 604 | |||
355 | 605 | private: | ||
356 | 606 | |||
357 | 607 | virtual bool Compare (int lhsPos, | ||
358 | 608 | int rhsPos) const = 0; | ||
359 | 609 | virtual void ExplainCompare (std::ostream *os) const = 0; | ||
360 | 610 | |||
361 | 611 | WindowArray array; | ||
362 | 612 | unsigned int arrayNum; | ||
363 | 613 | Window cmp; | ||
364 | 614 | |||
365 | 615 | }; | ||
366 | 616 | |||
367 | 617 | StackPositionMatcher::StackPositionMatcher (const WindowArray &array, | ||
368 | 618 | Window cmp, | ||
369 | 619 | unsigned int n) : | ||
370 | 620 | array (array), | ||
371 | 621 | arrayNum (n), | ||
372 | 622 | cmp (cmp) | ||
373 | 623 | { | ||
374 | 624 | } | ||
375 | 625 | |||
376 | 626 | bool | ||
377 | 627 | StackPositionMatcher::MatchAndExplain (Window window, | ||
378 | 628 | MatchResultListener *listener) const | ||
379 | 629 | { | ||
380 | 630 | int lhsPos = -1, rhsPos = -1; | ||
381 | 631 | |||
382 | 632 | for (unsigned int i = 0; i < arrayNum; ++i) | ||
383 | 633 | { | ||
384 | 634 | if (array[i] == window) | ||
385 | 635 | lhsPos = i; | ||
386 | 636 | if (array[i] == cmp) | ||
387 | 637 | rhsPos = i; | ||
388 | 638 | } | ||
389 | 639 | |||
390 | 640 | if (lhsPos > -1 && | ||
391 | 641 | rhsPos > -1) | ||
392 | 642 | { | ||
393 | 643 | if (Compare (lhsPos, rhsPos)) | ||
394 | 644 | return true; | ||
395 | 645 | } | ||
396 | 646 | |||
397 | 647 | /* Match failed, add stack to MatchResultListener */ | ||
398 | 648 | if (listener->IsInterested ()) | ||
399 | 649 | { | ||
400 | 650 | std::stringstream windowStack; | ||
401 | 651 | |||
402 | 652 | windowStack << "Window Stack (bottom to top [" | ||
403 | 653 | << arrayNum | ||
404 | 654 | << "]): \n"; | ||
405 | 655 | *listener << windowStack.str (); | ||
406 | 656 | for (unsigned int i = 0; i < arrayNum; ++i) | ||
407 | 657 | { | ||
408 | 658 | std::stringstream ss; | ||
409 | 659 | ss << " - 0x" | ||
410 | 660 | << std::hex | ||
411 | 661 | << array[i] | ||
412 | 662 | << std::dec | ||
413 | 663 | << std::endl; | ||
414 | 664 | *listener << ss.str (); | ||
415 | 665 | } | ||
416 | 666 | |||
417 | 667 | std::stringstream lhsPosMsg, rhsPosMsg; | ||
418 | 668 | |||
419 | 669 | lhsPosMsg << "Position of 0x" | ||
420 | 670 | << std::hex | ||
421 | 671 | << window | ||
422 | 672 | << std::dec | ||
423 | 673 | << " : " | ||
424 | 674 | << lhsPos; | ||
425 | 675 | |||
426 | 676 | rhsPosMsg << "Position of 0x" | ||
427 | 677 | << std::hex | ||
428 | 678 | << cmp | ||
429 | 679 | << std::dec | ||
430 | 680 | << " : " | ||
431 | 681 | << rhsPos; | ||
432 | 682 | |||
433 | 683 | *listener << lhsPosMsg.str () << "\n"; | ||
434 | 684 | *listener << rhsPosMsg.str () << "\n"; | ||
435 | 685 | } | ||
436 | 686 | |||
437 | 687 | return false; | ||
438 | 688 | } | ||
439 | 689 | |||
440 | 690 | void | ||
441 | 691 | StackPositionMatcher::DescribeTo (std::ostream *os) const | ||
442 | 692 | { | ||
443 | 693 | *os << "Window is "; | ||
444 | 694 | ExplainCompare (os); | ||
445 | 695 | *os << " in relation to 0x" << std::hex << cmp << std::dec; | ||
446 | 696 | } | ||
447 | 697 | |||
448 | 698 | class GreaterThanInStackMatcher : | ||
449 | 699 | public StackPositionMatcher | ||
450 | 700 | { | ||
451 | 701 | public: | ||
452 | 702 | |||
453 | 703 | GreaterThanInStackMatcher (const WindowArray &array, | ||
454 | 704 | Window cmp, | ||
455 | 705 | unsigned int n); | ||
456 | 706 | |||
457 | 707 | private: | ||
458 | 708 | |||
459 | 709 | bool Compare (int lhsPos, int rhsPos) const; | ||
460 | 710 | void ExplainCompare (std::ostream *os) const; | ||
461 | 711 | }; | ||
462 | 712 | |||
463 | 713 | GreaterThanInStackMatcher::GreaterThanInStackMatcher (const WindowArray &array, | ||
464 | 714 | Window cmp, | ||
465 | 715 | unsigned int n) : | ||
466 | 716 | StackPositionMatcher (array, cmp, n) | ||
467 | 717 | { | ||
468 | 718 | } | ||
469 | 719 | |||
470 | 720 | bool GreaterThanInStackMatcher::Compare (int lhsPos, int rhsPos) const | ||
471 | 721 | { | ||
472 | 722 | return lhsPos > rhsPos; | ||
473 | 723 | } | ||
474 | 724 | |||
475 | 725 | void GreaterThanInStackMatcher::ExplainCompare (std::ostream *os) const | ||
476 | 726 | { | ||
477 | 727 | *os << "greater than"; | ||
478 | 728 | } | ||
479 | 729 | |||
480 | 730 | class LessThanInStackMatcher : | ||
481 | 731 | public StackPositionMatcher | ||
482 | 732 | { | ||
483 | 733 | public: | ||
484 | 734 | |||
485 | 735 | LessThanInStackMatcher (const WindowArray &array, | ||
486 | 736 | Window cmp, | ||
487 | 737 | unsigned int n); | ||
488 | 738 | |||
489 | 739 | private: | ||
490 | 740 | |||
491 | 741 | bool Compare (int lhsPos, int rhsPos) const; | ||
492 | 742 | void ExplainCompare (std::ostream *os) const; | ||
493 | 743 | }; | ||
494 | 744 | |||
495 | 745 | LessThanInStackMatcher::LessThanInStackMatcher (const WindowArray &array, | ||
496 | 746 | Window cmp, | ||
497 | 747 | unsigned int n) : | ||
498 | 748 | StackPositionMatcher (array, cmp, n) | ||
499 | 749 | { | ||
500 | 750 | } | ||
501 | 751 | |||
502 | 752 | bool LessThanInStackMatcher::Compare (int lhsPos, int rhsPos) const | ||
503 | 753 | { | ||
504 | 754 | return lhsPos < rhsPos; | ||
505 | 755 | } | ||
506 | 756 | |||
507 | 757 | void LessThanInStackMatcher::ExplainCompare (std::ostream *os) const | ||
508 | 758 | { | ||
509 | 759 | *os << "less than"; | ||
510 | 760 | } | ||
511 | 761 | |||
512 | 762 | inline Matcher <Window> GreaterThanInStack (const WindowArray &array, | ||
513 | 763 | unsigned int n, | ||
514 | 764 | Window cmp) | ||
515 | 765 | { | ||
516 | 766 | return MakeMatcher (new GreaterThanInStackMatcher (array, cmp, n)); | ||
517 | 767 | } | ||
518 | 768 | |||
519 | 769 | inline Matcher <Window> LessThanInStack (const WindowArray &array, | ||
520 | 770 | unsigned int n, | ||
521 | 771 | Window cmp) | ||
522 | 772 | { | ||
523 | 773 | return MakeMatcher (new LessThanInStackMatcher (array, cmp, n)); | ||
524 | 774 | } | ||
525 | 775 | } | ||
526 | 776 | |||
527 | 777 | TEST_F (StackingSync, DestroyClientJustBeforeReparent) | ||
528 | 778 | { | ||
529 | 779 | ::Display *dpy = Display (); | ||
530 | 780 | |||
531 | 781 | ct::MessageAtoms atoms (dpy); | ||
532 | 782 | |||
533 | 783 | /* Set up three normal windows */ | ||
534 | 784 | Window w1 = CreateAndWaitForCreation (dpy); | ||
535 | 785 | Window w2 = CreateAndWaitForCreation (dpy); | ||
536 | 786 | Window w3 = CreateAndWaitForCreation (dpy); | ||
537 | 787 | |||
538 | 788 | Window p1 = MapAndWaitForParent (dpy, w1); | ||
539 | 789 | Window p2 = MapAndWaitForParent (dpy, w2); | ||
540 | 790 | Window p3 = MapAndWaitForParent (dpy, w3); | ||
541 | 791 | |||
542 | 792 | /* Create another normal window, but immediately mark | ||
543 | 793 | * it destroyed within compiz as soon as it is reparented, | ||
544 | 794 | * so that we force the reparented-but-destroyed strategy | ||
545 | 795 | * to kick in */ | ||
546 | 796 | Window destroyed = CreateAndWaitForCreation (dpy); | ||
547 | 797 | |||
548 | 798 | DestroyOnReparent (dpy, atoms, destroyed); | ||
549 | 799 | XMapRaised (dpy, destroyed); | ||
550 | 800 | |||
551 | 801 | /* Wait for the destroyed window's parent to be created | ||
552 | 802 | * in the toplevel stack as a result of the reparent operation */ | ||
553 | 803 | Window parentOfDestroyed = WaitForNextCreatedWindow (dpy); | ||
554 | 804 | WaitForManage (dpy, atoms); | ||
555 | 805 | |||
556 | 806 | /* Create an override redirect window and wait for it to be | ||
557 | 807 | * managed */ | ||
558 | 808 | Window override = CreateOverrideRedirectWindow (dpy); | ||
559 | 809 | WaitForManage (dpy, atoms); | ||
560 | 810 | |||
561 | 811 | /* Place the destroyed window's parent above | ||
562 | 812 | * p1 in the stack directly */ | ||
563 | 813 | RestackAbove (dpy, parentOfDestroyed, p1); | ||
564 | 814 | |||
565 | 815 | /* Ask compiz to place the override redirect window | ||
566 | 816 | * at least above the destroyed window's parent | ||
567 | 817 | * in the stack. This requires compiz to locate the | ||
568 | 818 | * destroyed window's parent in the stack */ | ||
569 | 819 | RestackAtLeastAbove (dpy, atoms, override, parentOfDestroyed); | ||
570 | 820 | |||
571 | 821 | /* Wait for the override window to be configured */ | ||
572 | 822 | Advance (dpy, | ||
573 | 823 | ct::WaitForEventOfTypeOnWindow (dpy, | ||
574 | 824 | override, | ||
575 | 825 | ConfigureNotify, | ||
576 | 826 | -1, | ||
577 | 827 | -1)); | ||
578 | 828 | |||
579 | 829 | unsigned int n; | ||
580 | 830 | WindowArray windows (GetChildren (dpy, DefaultRootWindow (dpy), n)); | ||
581 | 831 | |||
582 | 832 | EXPECT_THAT (p2, LessThanInStack (windows, n, override)); | ||
583 | 833 | EXPECT_THAT (p3, GreaterThanInStack (windows, n, override)); | ||
584 | 834 | } | ||
585 | 432 | 835 | ||
586 | === modified file 'tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp' | |||
587 | --- tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp 2013-02-23 07:08:20 +0000 | |||
588 | +++ tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.cpp 2013-06-26 21:25:34 +0000 | |||
589 | @@ -50,6 +50,8 @@ | |||
590 | 50 | "_COMPIZ_TEST_HELPER_FRAME_EXTENTS_CHANGED", | 50 | "_COMPIZ_TEST_HELPER_FRAME_EXTENTS_CHANGED", |
591 | 51 | "_COMPIZ_TEST_HELPER_CONFIGURE_WINDOW", | 51 | "_COMPIZ_TEST_HELPER_CONFIGURE_WINDOW", |
592 | 52 | "_COMPIZ_TEST_HELPER_WINDOW_CONFIGURE_PROCESSED", | 52 | "_COMPIZ_TEST_HELPER_WINDOW_CONFIGURE_PROCESSED", |
593 | 53 | "_COMPIZ_TEST_HELPER_DESTROY_ON_REPARENT", | ||
594 | 54 | "_COMPIZ_TEST_HELPER_RESTACK_ATLEAST_ABOVE", | ||
595 | 53 | "_COMPIZ_TEST_HELPER_WINDOW_READY" | 55 | "_COMPIZ_TEST_HELPER_WINDOW_READY" |
596 | 54 | }; | 56 | }; |
597 | 55 | } | 57 | } |
598 | @@ -61,7 +63,9 @@ | |||
599 | 61 | const char *TEST_HELPER_FRAME_EXTENTS_CHANGED = internal::messages[4]; | 63 | const char *TEST_HELPER_FRAME_EXTENTS_CHANGED = internal::messages[4]; |
600 | 62 | const char *TEST_HELPER_CONFIGURE_WINDOW = internal::messages[5]; | 64 | const char *TEST_HELPER_CONFIGURE_WINDOW = internal::messages[5]; |
601 | 63 | const char *TEST_HELPER_WINDOW_CONFIGURE_PROCESSED = internal::messages[6]; | 65 | const char *TEST_HELPER_WINDOW_CONFIGURE_PROCESSED = internal::messages[6]; |
603 | 64 | const char *TEST_HELPER_WINDOW_READY = internal::messages[7]; | 66 | const char *TEST_HELPER_DESTROY_ON_REPARENT = internal::messages[7]; |
604 | 67 | const char *TEST_HELPER_RESTACK_ATLEAST_ABOVE = internal::messages[8]; | ||
605 | 68 | const char *TEST_HELPER_WINDOW_READY = internal::messages[9]; | ||
606 | 65 | } | 69 | } |
607 | 66 | } | 70 | } |
608 | 67 | } | 71 | } |
609 | 68 | 72 | ||
610 | === modified file 'tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h' | |||
611 | --- tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h 2013-02-23 07:08:20 +0000 | |||
612 | +++ tests/xorg-gtest/communicator/compiz_xorg_gtest_communicator.h 2013-06-26 21:25:34 +0000 | |||
613 | @@ -41,6 +41,8 @@ | |||
614 | 41 | extern const char *TEST_HELPER_FRAME_EXTENTS_CHANGED; | 41 | extern const char *TEST_HELPER_FRAME_EXTENTS_CHANGED; |
615 | 42 | extern const char *TEST_HELPER_CONFIGURE_WINDOW; | 42 | extern const char *TEST_HELPER_CONFIGURE_WINDOW; |
616 | 43 | extern const char *TEST_HELPER_WINDOW_CONFIGURE_PROCESSED; | 43 | extern const char *TEST_HELPER_WINDOW_CONFIGURE_PROCESSED; |
617 | 44 | extern const char *TEST_HELPER_DESTROY_ON_REPARENT; | ||
618 | 45 | extern const char *TEST_HELPER_RESTACK_ATLEAST_ABOVE; | ||
619 | 44 | extern const char *TEST_HELPER_WINDOW_READY; | 46 | extern const char *TEST_HELPER_WINDOW_READY; |
620 | 45 | } | 47 | } |
621 | 46 | 48 | ||
622 | 47 | 49 | ||
623 | === modified file 'tests/xorg-gtest/include/compiz-xorg-gtest.h' | |||
624 | --- tests/xorg-gtest/include/compiz-xorg-gtest.h 2013-06-22 12:27:36 +0000 | |||
625 | +++ tests/xorg-gtest/include/compiz-xorg-gtest.h 2013-06-26 21:25:34 +0000 | |||
626 | @@ -125,6 +125,8 @@ | |||
627 | 125 | Window GetImmediateParent (Display *display, | 125 | Window GetImmediateParent (Display *display, |
628 | 126 | Window w, | 126 | Window w, |
629 | 127 | Window &rootReturn); | 127 | Window &rootReturn); |
630 | 128 | Window GetTopmostNonRootParent (Display *display, | ||
631 | 129 | Window w); | ||
632 | 128 | 130 | ||
633 | 129 | std::list <Window> NET_CLIENT_LIST_STACKING (Display *); | 131 | std::list <Window> NET_CLIENT_LIST_STACKING (Display *); |
634 | 130 | bool AdvanceToNextEventOnSuccess (Display *dpy, | 132 | bool AdvanceToNextEventOnSuccess (Display *dpy, |
635 | 131 | 133 | ||
636 | === modified file 'tests/xorg-gtest/plugins/testhelper/src/testhelper.cpp' | |||
637 | --- tests/xorg-gtest/plugins/testhelper/src/testhelper.cpp 2013-05-09 13:43:07 +0000 | |||
638 | +++ tests/xorg-gtest/plugins/testhelper/src/testhelper.cpp 2013-06-26 21:25:34 +0000 | |||
639 | @@ -181,10 +181,66 @@ | |||
640 | 181 | } | 181 | } |
641 | 182 | } | 182 | } |
642 | 183 | 183 | ||
643 | 184 | void | ||
644 | 185 | TestHelperWindow::setDestroyOnReparent (long *) | ||
645 | 186 | { | ||
646 | 187 | destroyOnReparent = true; | ||
647 | 188 | } | ||
648 | 189 | |||
649 | 190 | void | ||
650 | 191 | TestHelperWindow::restackAtLeastAbove (long *data) | ||
651 | 192 | { | ||
652 | 193 | ServerLock lock (screen->serverGrabInterface ()); | ||
653 | 194 | |||
654 | 195 | Window above = data[0]; | ||
655 | 196 | XWindowAttributes attrib; | ||
656 | 197 | |||
657 | 198 | if (!XGetWindowAttributes (screen->dpy (), above, &attrib)) | ||
658 | 199 | return; | ||
659 | 200 | |||
660 | 201 | CompWindow *w = screen->findTopLevelWindow (above, true); | ||
661 | 202 | for (; w; w = w->next) | ||
662 | 203 | if (!w->overrideRedirect ()) | ||
663 | 204 | break; | ||
664 | 205 | |||
665 | 206 | if (!w) | ||
666 | 207 | return; | ||
667 | 208 | |||
668 | 209 | XWindowChanges xwc; | ||
669 | 210 | |||
670 | 211 | xwc.stack_mode = Above; | ||
671 | 212 | xwc.sibling = w->frame () ? w->frame () : w->id (); | ||
672 | 213 | |||
673 | 214 | window->restackAndConfigureXWindow (CWStackMode | CWSibling, | ||
674 | 215 | &xwc, | ||
675 | 216 | lock); | ||
676 | 217 | } | ||
677 | 218 | |||
678 | 219 | void | ||
679 | 220 | TestHelperWindow::windowNotify (CompWindowNotify n) | ||
680 | 221 | { | ||
681 | 222 | switch (n) | ||
682 | 223 | { | ||
683 | 224 | case CompWindowNotifyReparent: | ||
684 | 225 | if (destroyOnReparent) | ||
685 | 226 | { | ||
686 | 227 | Window id = window->id (); | ||
687 | 228 | window->destroy (); | ||
688 | 229 | XDestroyWindow (screen->dpy (), id); | ||
689 | 230 | } | ||
690 | 231 | break; | ||
691 | 232 | default: | ||
692 | 233 | break; | ||
693 | 234 | } | ||
694 | 235 | |||
695 | 236 | window->windowNotify (n); | ||
696 | 237 | } | ||
697 | 238 | |||
698 | 184 | TestHelperWindow::TestHelperWindow (CompWindow *w) : | 239 | TestHelperWindow::TestHelperWindow (CompWindow *w) : |
699 | 185 | PluginClassHandler <TestHelperWindow, CompWindow> (w), | 240 | PluginClassHandler <TestHelperWindow, CompWindow> (w), |
700 | 186 | window (w), | 241 | window (w), |
702 | 187 | configureLock () | 242 | configureLock (), |
703 | 243 | destroyOnReparent (false) | ||
704 | 188 | { | 244 | { |
705 | 189 | WindowInterface::setHandler (w); | 245 | WindowInterface::setHandler (w); |
706 | 190 | 246 | ||
707 | @@ -214,6 +270,10 @@ | |||
708 | 214 | &TestHelperWindow::setFrameExtentsAndReport); | 270 | &TestHelperWindow::setFrameExtentsAndReport); |
709 | 215 | watchForMessage (fetchAtom (ctm::TEST_HELPER_LOCK_CONFIGURE_REQUESTS), | 271 | watchForMessage (fetchAtom (ctm::TEST_HELPER_LOCK_CONFIGURE_REQUESTS), |
710 | 216 | &TestHelperWindow::setConfigureLock); | 272 | &TestHelperWindow::setConfigureLock); |
711 | 273 | watchForMessage (fetchAtom (ctm::TEST_HELPER_DESTROY_ON_REPARENT), | ||
712 | 274 | &TestHelperWindow::setDestroyOnReparent); | ||
713 | 275 | watchForMessage (fetchAtom (ctm::TEST_HELPER_RESTACK_ATLEAST_ABOVE), | ||
714 | 276 | &TestHelperWindow::restackAtLeastAbove); | ||
715 | 217 | 277 | ||
716 | 218 | ct::SendClientMessage (s->dpy (), | 278 | ct::SendClientMessage (s->dpy (), |
717 | 219 | mAtomStore.FetchForString (ctm::TEST_HELPER_READY_MSG), | 279 | mAtomStore.FetchForString (ctm::TEST_HELPER_READY_MSG), |
718 | 220 | 280 | ||
719 | === modified file 'tests/xorg-gtest/plugins/testhelper/src/testhelper.h' | |||
720 | --- tests/xorg-gtest/plugins/testhelper/src/testhelper.h 2013-02-14 12:12:53 +0000 | |||
721 | +++ tests/xorg-gtest/plugins/testhelper/src/testhelper.h 2013-06-26 21:25:34 +0000 | |||
722 | @@ -77,11 +77,17 @@ | |||
723 | 77 | void configureAndReport (long *); | 77 | void configureAndReport (long *); |
724 | 78 | void setFrameExtentsAndReport (long *); | 78 | void setFrameExtentsAndReport (long *); |
725 | 79 | void setConfigureLock (long *); | 79 | void setConfigureLock (long *); |
726 | 80 | void setDestroyOnReparent (long *); | ||
727 | 81 | void restackAtLeastAbove (long *); | ||
728 | 80 | 82 | ||
729 | 81 | private: | 83 | private: |
730 | 82 | 84 | ||
731 | 85 | void windowNotify (CompWindowNotify n); | ||
732 | 86 | |||
733 | 83 | CompWindow *window; | 87 | CompWindow *window; |
734 | 84 | compiz::window::configure_buffers::Releasable::Ptr configureLock; | 88 | compiz::window::configure_buffers::Releasable::Ptr configureLock; |
735 | 89 | |||
736 | 90 | bool destroyOnReparent; | ||
737 | 85 | }; | 91 | }; |
738 | 86 | 92 | ||
739 | 87 | class TestHelperPluginVTable : | 93 | class TestHelperPluginVTable : |
740 | 88 | 94 | ||
741 | === modified file 'tests/xorg-gtest/src/compiz-xorg-gtest.cpp' | |||
742 | --- tests/xorg-gtest/src/compiz-xorg-gtest.cpp 2013-06-22 12:27:36 +0000 | |||
743 | +++ tests/xorg-gtest/src/compiz-xorg-gtest.cpp 2013-06-26 21:25:34 +0000 | |||
744 | @@ -105,6 +105,27 @@ | |||
745 | 105 | return parentReturn; | 105 | return parentReturn; |
746 | 106 | } | 106 | } |
747 | 107 | 107 | ||
748 | 108 | Window | ||
749 | 109 | ct::GetTopmostNonRootParent (Display *display, | ||
750 | 110 | Window w) | ||
751 | 111 | { | ||
752 | 112 | Window rootReturn = 0; | ||
753 | 113 | Window parentReturn = w; | ||
754 | 114 | Window lastParent = 0; | ||
755 | 115 | |||
756 | 116 | do | ||
757 | 117 | { | ||
758 | 118 | lastParent = parentReturn; | ||
759 | 119 | |||
760 | 120 | parentReturn = GetImmediateParent (display, | ||
761 | 121 | lastParent, | ||
762 | 122 | rootReturn); | ||
763 | 123 | |||
764 | 124 | } while (parentReturn != rootReturn); | ||
765 | 125 | |||
766 | 126 | return lastParent; | ||
767 | 127 | } | ||
768 | 128 | |||
769 | 108 | bool | 129 | bool |
770 | 109 | ct::AdvanceToNextEventOnSuccess (Display *dpy, | 130 | ct::AdvanceToNextEventOnSuccess (Display *dpy, |
771 | 110 | bool waitResult) | 131 | bool waitResult) |
FAILED: Continuous integration, rev:3747 jenkins. qa.ubuntu. com/job/ compiz- ci/215/ jenkins. qa.ubuntu. com/job/ compiz- gles-ci/ ./build= pbuilder, distribution= raring, flavor= amd64/256/ console jenkins. qa.ubuntu. com/job/ compiz- saucy-amd64- ci/28 jenkins. qa.ubuntu. com/job/ compiz- saucy-armhf- ci/28 jenkins. qa.ubuntu. com/job/ compiz- saucy-i386- ci/28
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ compiz- ci/215/ rebuild
http://