Merge lp:~compiz-team/compiz-core/compiz-core.fix_860304 into lp:compiz-core/0.9.5
- compiz-core.fix_860304
- Merge into 0.9.5
Proposed by
Sam Spilsbury
Status: | Merged |
---|---|
Merged at revision: | 2842 |
Proposed branch: | lp:~compiz-team/compiz-core/compiz-core.fix_860304 |
Merge into: | lp:compiz-core/0.9.5 |
Diff against target: |
1020 lines (+538/-117) 6 files modified
plugins/move/src/move.cpp (+28/-1) plugins/move/src/move.h (+7/-1) src/privatewindow.h (+9/-0) src/screen.cpp (+14/-7) src/stackdebugger.cpp (+4/-0) src/window.cpp (+476/-108) |
To merge this branch: | bzr merge lp:~compiz-team/compiz-core/compiz-core.fix_860304 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Robert Carr (community) | Approve | ||
Review via email: mp+77156@code.launchpad.net |
Commit message
Description of the change
Fix bug 860304
To post a comment you must log in.
Revision history for this message
David Barth (dbarth) wrote : | # |
The code changes are massive: is that some parts that you've taken from elsewhere and can be trusted to be well tested already? Or is it all brand new code? The worst would be to add crashers.
- 2840. By Sam Spilsbury
-
Fix typoes
- 2841. By Sam Spilsbury
-
Added a workaround to ensure that we don't end up with stale configure requests
causing windows to always be moved asynchronously (slow)
Revision history for this message
Carey Underwood (cwillu) wrote : | # |
Something in this appears to have made moving windows quite slow, and frequently preventing the window (or any other windows for that matter) from updating while the mouse is still moving. Enabling sync to vrefresh makes it much worse. Disabling the unityshell plugin temporarily immediately restores silky smooth behaviour.
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-06-23 03:22:47 +0000 |
3 | +++ plugins/move/src/move.cpp 2011-09-27 15:45:28 +0000 |
4 | @@ -488,7 +488,8 @@ |
5 | wY + dy - w->geometry ().y (), false); |
6 | |
7 | if (ms->optionGetLazyPositioning () && |
8 | - MoveScreen::get (screen)->hasCompositing) |
9 | + ms->hasCompositing && |
10 | + !MoveWindow::get (ms->w)->mLocked) |
11 | { |
12 | /* FIXME: This form of lazy positioning is broken and should |
13 | be replaced asap. Current code exists just to avoid a |
14 | @@ -507,6 +508,32 @@ |
15 | } |
16 | } |
17 | |
18 | +/* FIXME: This is a hack to prevent a race condition |
19 | + * when core is processing ConfigureNotify events. It |
20 | + * MUST be removed after 0.9.6 when we can break ABI |
21 | + * and do lazy positioning correctly ! */ |
22 | + |
23 | +void |
24 | +MoveScreen::handleCompizEvent (const char *plugin, const char *event, CompOption::Vector &options) |
25 | +{ |
26 | + if (w) |
27 | + { |
28 | + if (std::string ("core") == std::string (plugin)) |
29 | + { |
30 | + if (std::string ("lock_position") == std::string (event)) |
31 | + { |
32 | + Window xid = CompOption::getIntOptionNamed (options, "window", 0); |
33 | + int lock = CompOption::getIntOptionNamed (options, "active", 0); |
34 | + |
35 | + if (xid == w->id ()) |
36 | + MoveWindow::get (w)->mLocked = lock ? true : false; |
37 | + } |
38 | + } |
39 | + } |
40 | + |
41 | + screen->handleCompizEvent (plugin, event, options); |
42 | +} |
43 | + |
44 | void |
45 | MoveScreen::handleEvent (XEvent *event) |
46 | { |
47 | |
48 | === modified file 'plugins/move/src/move.h' |
49 | --- plugins/move/src/move.h 2009-12-25 19:49:23 +0000 |
50 | +++ plugins/move/src/move.h 2011-09-27 15:45:28 +0000 |
51 | @@ -61,6 +61,9 @@ |
52 | void updateOpacity (); |
53 | |
54 | void handleEvent (XEvent *); |
55 | + void handleCompizEvent (const char *plugin, |
56 | + const char *event, |
57 | + CompOption::Vector &options); |
58 | |
59 | CompWindow *w; |
60 | int savedX; |
61 | @@ -98,7 +101,8 @@ |
62 | PluginClassHandler<MoveWindow,CompWindow> (window), |
63 | window (window), |
64 | gWindow (GLWindow::get (window)), |
65 | - cWindow (CompositeWindow::get (window)) |
66 | + cWindow (CompositeWindow::get (window)), |
67 | + mLocked (false) |
68 | { |
69 | if (gWindow) |
70 | GLWindowInterface::setHandler (gWindow, false); |
71 | @@ -110,6 +114,8 @@ |
72 | CompWindow *window; |
73 | GLWindow *gWindow; |
74 | CompositeWindow *cWindow; |
75 | + |
76 | + bool mLocked; |
77 | }; |
78 | |
79 | #define MOVE_SCREEN(s) \ |
80 | |
81 | === modified file 'src/privatewindow.h' |
82 | --- src/privatewindow.h 2011-09-25 04:16:18 +0000 |
83 | +++ src/privatewindow.h 2011-09-27 15:45:28 +0000 |
84 | @@ -211,6 +211,8 @@ |
85 | |
86 | void readIconHint (); |
87 | |
88 | + void addPendingConfigure (XWindowChanges &, unsigned int); |
89 | + |
90 | public: |
91 | |
92 | PrivateWindow *priv; |
93 | @@ -235,6 +237,8 @@ |
94 | XWindowAttributes attrib; |
95 | CompWindow::Geometry geometry; |
96 | CompWindow::Geometry serverGeometry; |
97 | + CompWindow::Geometry frameGeometry; |
98 | + CompWindow::Geometry serverFrameGeometry; |
99 | Window transientFor; |
100 | Window clientLeader; |
101 | XSizeHints sizeHints; |
102 | @@ -286,6 +290,11 @@ |
103 | int pendingUnmaps; |
104 | int pendingMaps; |
105 | |
106 | + typedef std::pair <XWindowChanges, unsigned int> XWCValueMask; |
107 | + |
108 | + std::list <XWCValueMask> pendingConfigures; |
109 | + bool pendingPositionUpdates; |
110 | + |
111 | char *startupId; |
112 | char *resName; |
113 | char *resClass; |
114 | |
115 | === modified file 'src/screen.cpp' |
116 | --- src/screen.cpp 2011-09-25 04:16:18 +0000 |
117 | +++ src/screen.cpp 2011-09-27 15:45:28 +0000 |
118 | @@ -765,7 +765,7 @@ |
119 | compLogMessage ("core", CompLogLevelDebug, "however, this may be a false positive"); |
120 | } |
121 | |
122 | - if (dbg->serverWindowsChanged () && dbg->checkSanity (priv->serverWindows)) |
123 | + if (dbg->serverWindowsChanged () && dbg->checkSanity (priv->windows)) |
124 | compLogMessage ("core", CompLogLevelDebug, "windows are stacked incorrectly"); |
125 | } |
126 | } |
127 | @@ -1756,8 +1756,13 @@ |
128 | |
129 | if (moveX != 0 || moveY != 0) |
130 | { |
131 | - w->move (moveX, moveY, true); |
132 | - w->syncPosition (); |
133 | + unsigned int valueMask = CWX | CWY; |
134 | + XWindowChanges xwc; |
135 | + |
136 | + xwc.x = w->serverGeometry ().x () + moveX; |
137 | + xwc.y = w->serverGeometry ().y () + moveY; |
138 | + |
139 | + w->configureXWindow (valueMask, &xwc); |
140 | } |
141 | } |
142 | } |
143 | @@ -3502,6 +3507,9 @@ |
144 | |
145 | foreach (CompWindow *w, priv->windows) |
146 | { |
147 | + unsigned int valueMask = CWX | CWY; |
148 | + XWindowChanges xwc; |
149 | + |
150 | if (w->onAllViewports ()) |
151 | continue; |
152 | |
153 | @@ -3513,11 +3521,10 @@ |
154 | if (w->saveMask () & CWY) |
155 | w->saveWc ().y += pnt.y (); |
156 | |
157 | - /* move */ |
158 | - w->move (pnt.x (), pnt.y ()); |
159 | + xwc.x = w->serverGeometry ().x () + pnt.x (); |
160 | + xwc.y = w->serverGeometry ().y () + pnt.y (); |
161 | |
162 | - if (sync) |
163 | - w->syncPosition (); |
164 | + w->configureXWindow (valueMask, &xwc); |
165 | } |
166 | |
167 | if (sync) |
168 | |
169 | === modified file 'src/stackdebugger.cpp' |
170 | --- src/stackdebugger.cpp 2011-09-25 04:16:18 +0000 |
171 | +++ src/stackdebugger.cpp 2011-09-27 15:45:28 +0000 |
172 | @@ -330,6 +330,10 @@ |
173 | if (!w->managed ()) |
174 | continue; |
175 | |
176 | + /* ignore any windows that just got created */ |
177 | + if (!w->mapNum ()) |
178 | + continue; |
179 | + |
180 | /* determine the current layer */ |
181 | if (w->type () == CompWindowTypeDockMask) |
182 | { |
183 | |
184 | === modified file 'src/window.cpp' |
185 | --- src/window.cpp 2011-09-25 04:16:18 +0000 |
186 | +++ src/window.cpp 2011-09-27 15:45:28 +0000 |
187 | @@ -792,32 +792,60 @@ |
188 | void |
189 | PrivateWindow::updateFrameWindow () |
190 | { |
191 | + XWindowChanges xwc; |
192 | + unsigned int valueMask = CWX | CWY | CWWidth | CWHeight; |
193 | + |
194 | if (!serverFrame) |
195 | return; |
196 | |
197 | + |
198 | gettimeofday (&lastConfigureRequest, NULL); |
199 | + /* Flush any changes made to serverFrameGeometry or serverGeometry to the server |
200 | + * since there is a race condition where geometries will go out-of-sync with |
201 | + * window movement */ |
202 | + |
203 | + window->syncPosition (); |
204 | |
205 | if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom) |
206 | { |
207 | - int x, y, width, height; |
208 | int bw = serverGeometry.border () * 2; |
209 | |
210 | - x = serverGeometry.x () - serverInput.left; |
211 | - y = serverGeometry.y () - serverInput.top; |
212 | - width = serverGeometry.width () + serverInput.left + serverInput.right + bw; |
213 | - height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw; |
214 | + xwc.x = serverGeometry.x () - serverInput.left; |
215 | + xwc.y = serverGeometry.y () - serverInput.top; |
216 | + xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw; |
217 | + xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw; |
218 | |
219 | if (shaded) |
220 | height = serverInput.top + serverInput.bottom; |
221 | |
222 | + if (serverFrameGeometry.x () == xwc.x) |
223 | + valueMask &= ~(CWX); |
224 | + else |
225 | + serverFrameGeometry.setX (xwc.x); |
226 | + |
227 | + if (serverFrameGeometry.y () == xwc.y) |
228 | + valueMask &= ~(CWY); |
229 | + else |
230 | + serverFrameGeometry.setY (xwc.y); |
231 | + |
232 | + if (serverFrameGeometry.width () == xwc.width) |
233 | + valueMask &= ~(CWWidth); |
234 | + else |
235 | + serverFrameGeometry.setWidth (xwc.width); |
236 | + |
237 | + if (serverFrameGeometry.height () == xwc.height) |
238 | + valueMask &= ~(CWHeight); |
239 | + else |
240 | + serverFrameGeometry.setHeight (xwc.height); |
241 | + |
242 | + addPendingConfigure (xwc, valueMask); |
243 | + |
244 | + |
245 | /* Geometry is the same, so we're not going to get a ConfigureNotify |
246 | * event when the window is configured, which means that other plugins |
247 | * won't know that the client, frame and wrapper windows got shifted |
248 | * around (and might result in display corruption, eg in OpenGL */ |
249 | - if (geometry.x () - input.left == x && |
250 | - geometry.y () - input.top == y && |
251 | - geometry.width () + input.left + input.right + bw == width && |
252 | - geometry.height () + input.top + input.bottom + bw == height) |
253 | + if (valueMask == 0) |
254 | { |
255 | XConfigureEvent xev; |
256 | XWindowAttributes attrib; |
257 | @@ -876,8 +904,7 @@ |
258 | XSync (screen->dpy (), false); |
259 | } |
260 | else |
261 | - XMoveResizeWindow (screen->dpy (), serverFrame, x, y, width, height); |
262 | - |
263 | + XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc); |
264 | if (shaded) |
265 | { |
266 | XUnmapWindow (screen->dpy (), wrapper); |
267 | @@ -895,25 +922,44 @@ |
268 | } |
269 | else |
270 | { |
271 | - int x, y, width, height; |
272 | int bw = serverGeometry.border () * 2; |
273 | |
274 | - x = serverGeometry.x (); |
275 | - y = serverGeometry.y (); |
276 | - width = serverGeometry.width () + bw; |
277 | - height = serverGeometry.height () + bw; |
278 | + xwc.x = serverGeometry.x (); |
279 | + xwc.y = serverGeometry.y (); |
280 | + xwc.width = serverGeometry.width () + bw; |
281 | + xwc.height = serverGeometry.height () + bw; |
282 | |
283 | if (shaded) |
284 | height = 0; |
285 | |
286 | + if (serverFrameGeometry.x () == xwc.x) |
287 | + valueMask &= ~(CWX); |
288 | + else |
289 | + serverFrameGeometry.setX (xwc.x); |
290 | + |
291 | + if (serverFrameGeometry.y () == xwc.y) |
292 | + valueMask &= ~(CWY); |
293 | + else |
294 | + serverFrameGeometry.setY (xwc.y); |
295 | + |
296 | + if (serverFrameGeometry.width () == xwc.width) |
297 | + valueMask &= ~(CWWidth); |
298 | + else |
299 | + serverFrameGeometry.setWidth (xwc.width); |
300 | + |
301 | + if (serverFrameGeometry.height () == xwc.height) |
302 | + valueMask &= ~(CWHeight); |
303 | + else |
304 | + serverFrameGeometry.setHeight (xwc.height); |
305 | + |
306 | + addPendingConfigure (xwc, valueMask); |
307 | + |
308 | + |
309 | /* Geometry is the same, so we're not going to get a ConfigureNotify |
310 | * event when the window is configured, which means that other plugins |
311 | * won't know that the client, frame and wrapper windows got shifted |
312 | * around (and might result in display corruption, eg in OpenGL */ |
313 | - if (geometry.x () - input.left == x && |
314 | - geometry.y () - input.top == y && |
315 | - geometry.width () + input.left + input.right + bw == width && |
316 | - geometry.height () + input.top + input.bottom + bw == height) |
317 | + if (valueMask == 0) |
318 | { |
319 | XConfigureEvent xev; |
320 | XWindowAttributes attrib; |
321 | @@ -972,7 +1018,7 @@ |
322 | XSync (screen->dpy (), false); |
323 | } |
324 | else |
325 | - XMoveResizeWindow (screen->dpy (), serverFrame, x, y, width, height); |
326 | + XConfigureWindow (screen->dpy (), serverFrame, valueMask, &xwc); |
327 | |
328 | if (shaded) |
329 | { |
330 | @@ -1753,8 +1799,6 @@ |
331 | dwidth = gm.width () - priv->geometry.width (); |
332 | dheight = gm.height () - priv->geometry.height (); |
333 | |
334 | - gettimeofday (&priv->lastGeometryUpdate, NULL); |
335 | - |
336 | priv->geometry.set (gm.x (), gm.y (), |
337 | gm.width (), gm.height (), |
338 | gm.border ()); |
339 | @@ -1776,13 +1820,17 @@ |
340 | dx = gm.x () - priv->geometry.x (); |
341 | dy = gm.y () - priv->geometry.y (); |
342 | |
343 | - /* Don't move the window here if a plugin has already updated |
344 | - * the geometry of that window after the last time the server |
345 | - * was sent a configure request since the configureNotify we |
346 | - * receieve here will be out of date. Instead wait for the plugin |
347 | - * to call syncPosition again */ |
348 | - if (TIMEVALDIFF (&priv->lastConfigureRequest, &priv->lastGeometryUpdate)) |
349 | - move (dx, dy); |
350 | + priv->geometry.setX (gm.x ()); |
351 | + priv->geometry.setY (gm.y ()); |
352 | + |
353 | + priv->region.translate (dx, dy); |
354 | + priv->inputRegion.translate (dx, dy); |
355 | + if (!priv->frameRegion.isEmpty ()) |
356 | + priv->frameRegion.translate (dx, dy); |
357 | + |
358 | + priv->invisible = WINDOW_INVISIBLE (priv); |
359 | + |
360 | + moveNotify (dx, dy, true); |
361 | } |
362 | |
363 | updateFrameRegion (); |
364 | @@ -1911,11 +1959,35 @@ |
365 | void |
366 | PrivateWindow::configure (XConfigureEvent *ce) |
367 | { |
368 | + unsigned int valueMask = 0; |
369 | + |
370 | if (priv->frame) |
371 | return; |
372 | |
373 | + /* remove configure event from pending configures */ |
374 | + if (priv->geometry.x () != ce->x) |
375 | + valueMask |= CWX; |
376 | + |
377 | + if (priv->geometry.y () != ce->y) |
378 | + valueMask |= CWY; |
379 | + |
380 | + if (priv->geometry.width () != ce->width) |
381 | + valueMask |= CWWidth; |
382 | + |
383 | + if (priv->geometry.height () != ce->height) |
384 | + valueMask |= CWHeight; |
385 | + |
386 | + if (priv->geometry.border () != ce->border_width) |
387 | + valueMask |= CWBorderWidth; |
388 | + |
389 | + if (ROOTPARENT (window->prev) != ce->above) |
390 | + valueMask |= CWSibling | CWStackMode; |
391 | + |
392 | priv->attrib.override_redirect = ce->override_redirect; |
393 | |
394 | + priv->frameGeometry.set (ce->x, ce->y, ce->width, |
395 | + ce->height, ce->border_width); |
396 | + |
397 | if (priv->syncWait) |
398 | priv->syncGeometry.set (ce->x, ce->y, ce->width, ce->height, |
399 | ce->border_width); |
400 | @@ -1939,10 +2011,89 @@ |
401 | { |
402 | int x, y, width, height; |
403 | CompWindow *above; |
404 | + unsigned int valueMask = 0; |
405 | + bool handled = false; |
406 | |
407 | if (!priv->frame) |
408 | return; |
409 | |
410 | + /* remove configure event from pending configures */ |
411 | + if (priv->frameGeometry.x () != ce->x) |
412 | + valueMask |= CWX; |
413 | + |
414 | + if (priv->frameGeometry.y () != ce->y) |
415 | + valueMask |= CWY; |
416 | + |
417 | + if (priv->frameGeometry.width () != ce->width) |
418 | + valueMask |= CWWidth; |
419 | + |
420 | + if (priv->frameGeometry.height () != ce->height) |
421 | + valueMask |= CWHeight; |
422 | + |
423 | + if (priv->frameGeometry.border () != ce->border_width) |
424 | + valueMask |= CWBorderWidth; |
425 | + |
426 | + if (ROOTPARENT (window->prev) != ce->above) |
427 | + valueMask |= CWSibling | CWStackMode; |
428 | + |
429 | + for (std::list <XWCValueMask>::iterator it = pendingConfigures.begin (); |
430 | + it != pendingConfigures.end (); it++) |
431 | + { |
432 | + XWCValueMask &xwcvm = (*it); |
433 | + |
434 | + |
435 | + if (xwcvm.second != valueMask) |
436 | + { |
437 | + /* For stacking cases, if a client wants to raise or lower a window |
438 | + * then they don't need to specify CWSibling, so allow that to be |
439 | + * excluded in those cases */ |
440 | + |
441 | + if (ce->above == ROOTPARENT (screen->windows ().back ()) || |
442 | + ce->above == 0) |
443 | + { |
444 | + if ((xwcvm.second & ~(CWSibling) != valueMask)) |
445 | + continue; |
446 | + } |
447 | + else |
448 | + continue; |
449 | + } |
450 | + |
451 | + if (xwcvm.second & CWX && xwcvm.first.x != ce->x) |
452 | + continue; |
453 | + |
454 | + if (xwcvm.second & CWY && xwcvm.first.y != ce->y) |
455 | + continue; |
456 | + |
457 | + if (xwcvm.second & CWWidth && xwcvm.first.width != ce->width) |
458 | + continue; |
459 | + |
460 | + if (xwcvm.second & CWHeight && xwcvm.first.height != ce->height) |
461 | + continue; |
462 | + |
463 | + if (xwcvm.second & (CWStackMode | CWSibling) && xwcvm.first.sibling != ce->above) |
464 | + continue; |
465 | + |
466 | + /* Matched ConfigureWindow request to ConfigureNotify event |
467 | + * remove it from the list */ |
468 | + |
469 | + handled = true; |
470 | + |
471 | + pendingConfigures.erase (it); |
472 | + break; |
473 | + } |
474 | + |
475 | + if (!handled) |
476 | + { |
477 | + compLogMessage ("core", CompLogLevelWarn, "unhandled ConfigureNotify on 0x%x!", serverFrame); |
478 | + compLogMessage ("core", CompLogLevelWarn, "this should never happen. you should"\ |
479 | + "probably file a bug about this."); |
480 | +#ifdef DEBUG |
481 | + abort (); |
482 | +#else |
483 | + pendingConfigures.clear (); |
484 | +#endif |
485 | + } |
486 | + |
487 | /* subtract the input extents last sent to the |
488 | * server to calculate the client size and then |
489 | * re-sync the input extents and extents last |
490 | @@ -1953,19 +2104,14 @@ |
491 | width = ce->width - priv->serverGeometry.border () * 2 - priv->serverInput.left - priv->serverInput.right; |
492 | height = ce->height - priv->serverGeometry.border () * 2 - priv->serverInput.top - priv->serverInput.bottom; |
493 | |
494 | + /* set the frame geometry */ |
495 | + priv->frameGeometry.set (ce->x, ce->y, ce->width, ce->height, ce->border_width); |
496 | + |
497 | + |
498 | if (priv->syncWait) |
499 | - { |
500 | priv->syncGeometry.set (x, y, width, height, ce->border_width); |
501 | - } |
502 | else |
503 | - { |
504 | - if (ce->override_redirect) |
505 | - { |
506 | - priv->serverGeometry.set (x, y, width, height, ce->border_width); |
507 | - } |
508 | - |
509 | window->resize (x, y, width, height, ce->border_width); |
510 | - } |
511 | |
512 | if (priv->restack (ce->above)) |
513 | priv->updatePassiveButtonGrabs (); |
514 | @@ -1974,6 +2120,27 @@ |
515 | |
516 | if (above) |
517 | above->priv->updatePassiveButtonGrabs (); |
518 | + |
519 | + if (pendingConfigures.empty ()) |
520 | + { |
521 | + /* Tell plugins its ok to start doing stupid things again but |
522 | + * obviously FIXME */ |
523 | + CompOption::Vector options; |
524 | + CompOption::Value v; |
525 | + |
526 | + options.push_back (CompOption ("window", CompOption::TypeInt)); |
527 | + v.set ((int) id); |
528 | + options.back ().set (v); |
529 | + options.push_back (CompOption ("active", CompOption::TypeInt)); |
530 | + v.set ((int) 0); |
531 | + options.back ().set (v); |
532 | + |
533 | + /* Notify other plugins that it is unsafe to change geometry or serverGeometry |
534 | + * FIXME: That API should not be accessible to plugins, this is a hack to avoid |
535 | + * breaking ABI */ |
536 | + |
537 | + screen->handleCompizEvent ("core", "lock_position", options); |
538 | + } |
539 | } |
540 | |
541 | void |
542 | @@ -1996,43 +2163,129 @@ |
543 | { |
544 | if (dx || dy) |
545 | { |
546 | - /* |
547 | - priv->attrib.x += dx; |
548 | - priv->attrib.y += dy; |
549 | - */ |
550 | - priv->geometry.setX (priv->geometry.x () + dx); |
551 | - priv->geometry.setY (priv->geometry.y () + dy); |
552 | - |
553 | gettimeofday (&priv->lastGeometryUpdate, NULL); |
554 | |
555 | - priv->region.translate (dx, dy); |
556 | - priv->inputRegion.translate (dx, dy); |
557 | - if (!priv->frameRegion.isEmpty ()) |
558 | - priv->frameRegion.translate (dx, dy); |
559 | - |
560 | - priv->invisible = WINDOW_INVISIBLE (priv); |
561 | - |
562 | - moveNotify (dx, dy, immediate); |
563 | + /* Don't allow window movement to overwrite working geometries |
564 | + * last received from the server if we know there are pending |
565 | + * ConfigureNotify events on this window. That's a clunky workaround |
566 | + * and a FIXME in any case, however, until we can break the API |
567 | + * and remove CompWindow::move, this will need to be the case */ |
568 | + |
569 | + if (!priv->pendingConfigures.size ()) |
570 | + { |
571 | + priv->geometry.setX (priv->geometry.x () + dx); |
572 | + priv->geometry.setY (priv->geometry.y () + dy); |
573 | + priv->frameGeometry.setX (priv->frameGeometry.x () + dx); |
574 | + priv->frameGeometry.setY (priv->frameGeometry.y () + dy); |
575 | + |
576 | + priv->pendingPositionUpdates = true; |
577 | + |
578 | + priv->region.translate (dx, dy); |
579 | + priv->inputRegion.translate (dx, dy); |
580 | + if (!priv->frameRegion.isEmpty ()) |
581 | + priv->frameRegion.translate (dx, dy); |
582 | + |
583 | + priv->invisible = WINDOW_INVISIBLE (priv); |
584 | + |
585 | + moveNotify (dx, dy, immediate); |
586 | + } |
587 | + else |
588 | + { |
589 | + XWindowChanges xwc; |
590 | + unsigned int valueMask = CWX | CWY; |
591 | + struct timeval tv, old; |
592 | + compLogMessage ("core", CompLogLevelDebug, "pending configure notifies on 0x%x,"\ |
593 | + "moving window asyncrhonously!", (unsigned int) priv->serverId); |
594 | + |
595 | + old = priv->lastConfigureRequest; |
596 | + gettimeofday (&tv, NULL); |
597 | + |
598 | + xwc.x = priv->serverGeometry.x () + dx; |
599 | + xwc.y = priv->serverGeometry.y () + dy; |
600 | + |
601 | + configureXWindow (valueMask, &xwc); |
602 | + |
603 | + priv->lastConfigureRequest = old; |
604 | + |
605 | + /* FIXME: This is a hack to avoid performance regressions |
606 | + * and must be removed in 0.9.6 */ |
607 | + if (tv.tv_usec - priv->lastConfigureRequest.tv_usec > 30000) |
608 | + { |
609 | + compLogMessage ("core", CompLogLevelWarn, "failed to receive ConfigureNotify event from request at %i (now: %i)\n", |
610 | + priv->lastConfigureRequest.tv_usec, tv.tv_usec); |
611 | + priv->pendingConfigures.clear (); |
612 | + } |
613 | + } |
614 | } |
615 | } |
616 | |
617 | void |
618 | +PrivateWindow::addPendingConfigure (XWindowChanges &xwc, unsigned int valueMask) |
619 | +{ |
620 | + CompOption::Vector options; |
621 | + CompOption::Value v; |
622 | + |
623 | + options.push_back (CompOption ("window", CompOption::TypeInt)); |
624 | + v.set ((int) id); |
625 | + options.back ().set (v); |
626 | + options.push_back (CompOption ("active", CompOption::TypeInt)); |
627 | + v.set ((int) 1); |
628 | + options.back ().set (v); |
629 | + |
630 | + gettimeofday (&lastConfigureRequest, NULL); |
631 | + |
632 | + /* Notify other plugins that it is unsafe to change geometry or serverGeometry |
633 | + * FIXME: That API should not be accessible to plugins, this is a hack to avoid |
634 | + * breaking ABI */ |
635 | + |
636 | + screen->handleCompizEvent ("core", "lock_position", options); |
637 | + |
638 | + priv->pendingConfigures.push_back (XWCValueMask (xwc, valueMask)); |
639 | +} |
640 | + |
641 | +void |
642 | CompWindow::syncPosition () |
643 | { |
644 | - priv->serverGeometry.setX (priv->geometry.x ()); |
645 | - priv->serverGeometry.setY (priv->geometry.y ()); |
646 | - |
647 | gettimeofday (&priv->lastConfigureRequest, NULL); |
648 | |
649 | - XMoveWindow (screen->dpy (), ROOTPARENT (this), |
650 | - priv->serverGeometry.x () - priv->serverInput.left, |
651 | - priv->serverGeometry.y () - priv->serverInput.top); |
652 | + unsigned int valueMask = CWX | CWY; |
653 | + XWindowChanges xwc; |
654 | |
655 | - if (priv->serverFrame) |
656 | + if (priv->pendingPositionUpdates && priv->pendingConfigures.empty ()) |
657 | { |
658 | - XMoveWindow (screen->dpy (), priv->wrapper, |
659 | - priv->serverInput.left, priv->serverInput.top); |
660 | - sendConfigureNotify (); |
661 | + if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ()) |
662 | + valueMask &= ~(CWX); |
663 | + if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ()) |
664 | + valueMask &= ~(CWY); |
665 | + |
666 | + /* Because CompWindow::move can update the geometry last |
667 | + * received from the server, we must indicate that no values |
668 | + * changed, because when the ConfigureNotify comes around |
669 | + * the values are going to be the same. That's obviously |
670 | + * broken behaviour and worthy of a FIXME, but requires |
671 | + * larger changes to the window movement system. */ |
672 | + if (valueMask) |
673 | + { |
674 | + priv->addPendingConfigure (xwc, 0); |
675 | + |
676 | + priv->serverGeometry.setX (priv->geometry.x ()); |
677 | + priv->serverGeometry.setY (priv->geometry.y ()); |
678 | + priv->serverFrameGeometry.setX (priv->frameGeometry.x ()); |
679 | + priv->serverFrameGeometry.setY (priv->frameGeometry.y ()); |
680 | + |
681 | + xwc.x = priv->serverFrameGeometry.x (); |
682 | + xwc.y = priv->serverFrameGeometry.y (); |
683 | + |
684 | + XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc); |
685 | + |
686 | + if (priv->serverFrame) |
687 | + { |
688 | + XMoveWindow (screen->dpy (), priv->wrapper, |
689 | + priv->serverInput.left, priv->serverInput.top); |
690 | + sendConfigureNotify (); |
691 | + } |
692 | + } |
693 | + priv->pendingPositionUpdates = false; |
694 | } |
695 | } |
696 | |
697 | @@ -2185,11 +2438,13 @@ |
698 | vp = defaultViewport (); |
699 | if (screen->vp () != vp) |
700 | { |
701 | - int moveX = (screen->vp ().x () - vp.x ()) * screen->width (); |
702 | - int moveY = (screen->vp ().y () - vp.y ()) * screen->height (); |
703 | - |
704 | - move (moveX, moveY, TRUE); |
705 | - syncPosition (); |
706 | + unsigned int valueMask = CWX | CWY; |
707 | + XWindowChanges xwc; |
708 | + |
709 | + xwc.x = serverGeometry ().x () + (screen->vp ().x () - vp.x ()) * screen->width (); |
710 | + xwc.y = serverGeometry ().y () + (screen->vp ().y () - vp.y ()) * screen->height (); |
711 | + |
712 | + configureXWindow (valueMask, &xwc); |
713 | } |
714 | } |
715 | } |
716 | @@ -2749,6 +3004,54 @@ |
717 | PrivateWindow::reconfigureXWindow (unsigned int valueMask, |
718 | XWindowChanges *xwc) |
719 | { |
720 | + unsigned int frameValueMask = valueMask; |
721 | + |
722 | + /* Immediately sync window position |
723 | + * if plugins were updating w->geometry () directly |
724 | + * in order to avoid a race condition */ |
725 | + |
726 | + window->syncPosition (); |
727 | + |
728 | + /* Remove redundant bits */ |
729 | + |
730 | + if (serverGeometry.x () == xwc->x) |
731 | + valueMask &= ~(CWX); |
732 | + |
733 | + if (serverGeometry.y () == xwc->y) |
734 | + valueMask &= ~(CWY); |
735 | + |
736 | + if (serverGeometry.width () == xwc->width) |
737 | + valueMask &= ~(CWWidth); |
738 | + |
739 | + if (serverGeometry.height () == xwc->height) |
740 | + valueMask &= ~(CWHeight); |
741 | + |
742 | + if (serverGeometry.border () == xwc->border_width) |
743 | + valueMask &= ~(CWBorderWidth); |
744 | + |
745 | + if (window->serverPrev && ROOTPARENT (window->serverPrev) == xwc->sibling) |
746 | + { |
747 | + /* check if the sibling is also pending a restack, |
748 | + * if not, then setting this bit is useless */ |
749 | + |
750 | + bool pendingRestack = false; |
751 | + |
752 | + foreach (XWCValueMask &xwcvm, window->serverPrev->priv->pendingConfigures) |
753 | + { |
754 | + if (xwcvm.second & (CWSibling | CWStackMode)) |
755 | + { |
756 | + pendingRestack = true; |
757 | + break; |
758 | + } |
759 | + } |
760 | + |
761 | + if (!pendingRestack) |
762 | + valueMask &= ~(CWSibling | CWStackMode); |
763 | + } |
764 | + |
765 | + if (valueMask & CWBorderWidth) |
766 | + serverGeometry.setBorder (xwc->border_width); |
767 | + |
768 | if (valueMask & CWX) |
769 | serverGeometry.setX (xwc->x); |
770 | |
771 | @@ -2761,9 +3064,6 @@ |
772 | if (valueMask & CWHeight) |
773 | serverGeometry.setHeight (xwc->height); |
774 | |
775 | - if (valueMask & CWBorderWidth) |
776 | - serverGeometry.setBorder (xwc->border_width); |
777 | - |
778 | /* Update the server side window list on raise, lower and restack functions. |
779 | * This function should only recieve stack_mode == Above |
780 | * but warn incase something else does get through, to make the cause |
781 | @@ -2774,41 +3074,80 @@ |
782 | { |
783 | if (xwc->sibling) |
784 | { |
785 | - CompWindow *w = screen->findWindow (id); |
786 | - |
787 | - screen->unhookServerWindow (w); |
788 | - screen->insertServerWindow (w, xwc->sibling); |
789 | + screen->unhookServerWindow (window); |
790 | + screen->insertServerWindow (window, xwc->sibling); |
791 | } |
792 | } |
793 | else |
794 | compLogMessage ("core", CompLogLevelWarn, "restack_mode not Above"); |
795 | } |
796 | |
797 | + if (serverFrameGeometry.x () == xwc->x - serverGeometry.border () - serverInput.left) |
798 | + frameValueMask &= ~(CWX); |
799 | + |
800 | + if (serverFrameGeometry.y () == xwc->y - serverGeometry.border () - serverInput.top) |
801 | + frameValueMask &= ~(CWY); |
802 | + |
803 | + if (serverFrameGeometry.width () == xwc->width + serverGeometry.border () * 2 |
804 | + + serverInput.left + serverInput.right) |
805 | + frameValueMask &= ~(CWWidth); |
806 | + |
807 | + if (serverFrameGeometry.height () == xwc->height + serverGeometry.border () * 2 |
808 | + + serverInput.top + serverInput.bottom) |
809 | + frameValueMask &= ~(CWHeight); |
810 | + |
811 | + /* Can't set the border width of frame windows */ |
812 | + frameValueMask &= ~(CWBorderWidth); |
813 | + |
814 | + if (frameValueMask & CWX) |
815 | + serverFrameGeometry.setX (xwc->x - serverGeometry.border () - serverInput.left); |
816 | + |
817 | + if (frameValueMask & CWY) |
818 | + serverFrameGeometry.setY (xwc->y -serverGeometry.border () - serverInput.top); |
819 | + |
820 | + if (frameValueMask & CWWidth) |
821 | + serverFrameGeometry.setWidth (xwc->width + serverGeometry.border () * 2 |
822 | + + serverInput.left + serverInput.right); |
823 | + |
824 | + if (frameValueMask & CWHeight) |
825 | + serverFrameGeometry.setHeight (xwc->height + serverGeometry.border () * 2 |
826 | + + serverInput.top + serverInput.bottom); |
827 | + |
828 | + |
829 | if (serverFrame) |
830 | { |
831 | - XWindowChanges wc = *xwc; |
832 | - |
833 | gettimeofday (&lastConfigureRequest, NULL); |
834 | |
835 | - wc.x -= serverInput.left - serverGeometry.border (); |
836 | - wc.y -= serverInput.top - serverGeometry.border (); |
837 | - wc.width += serverInput.left + serverInput.right + serverGeometry.border (); |
838 | - wc.height += serverInput.top + serverInput.bottom + serverGeometry.border (); |
839 | - |
840 | - XConfigureWindow (screen->dpy (), serverFrame, valueMask, &wc); |
841 | + if (frameValueMask) |
842 | + { |
843 | + XWindowChanges wc = *xwc; |
844 | + |
845 | + wc.x = serverFrameGeometry.x (); |
846 | + wc.y = serverFrameGeometry.y (); |
847 | + wc.width = serverFrameGeometry.width (); |
848 | + wc.height = serverFrameGeometry.height (); |
849 | + |
850 | + addPendingConfigure (wc, frameValueMask); |
851 | + |
852 | + XConfigureWindow (screen->dpy (), serverFrame, frameValueMask, &wc); |
853 | + } |
854 | valueMask &= ~(CWSibling | CWStackMode); |
855 | |
856 | - xwc->x = serverInput.left; |
857 | - xwc->y = serverInput.top; |
858 | - XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc); |
859 | + if (valueMask) |
860 | + { |
861 | + xwc->x = serverInput.left; |
862 | + xwc->y = serverInput.top; |
863 | + XConfigureWindow (screen->dpy (), wrapper, valueMask, xwc); |
864 | |
865 | - xwc->x = 0; |
866 | - xwc->y = 0; |
867 | + xwc->x = 0; |
868 | + xwc->y = 0; |
869 | + } |
870 | |
871 | window->sendConfigureNotify (); |
872 | } |
873 | |
874 | - XConfigureWindow (screen->dpy (), id, valueMask, xwc); |
875 | + if (valueMask) |
876 | + XConfigureWindow (screen->dpy (), id, valueMask, xwc); |
877 | } |
878 | |
879 | bool |
880 | @@ -3574,9 +3913,30 @@ |
881 | * if serverPrev was recently restacked */ |
882 | if (window->serverPrev) |
883 | { |
884 | - if (!sibling) |
885 | - { |
886 | - XLowerWindow (screen->dpy (), ROOTPARENT (window)); |
887 | + bool pendingRestacks = false; |
888 | + |
889 | + foreach (XWCValueMask &xwcvm, sibling->priv->pendingConfigures) |
890 | + { |
891 | + if (xwcvm.second & (CWSibling | CWStackMode)) |
892 | + { |
893 | + pendingRestacks = true; |
894 | + break; |
895 | + } |
896 | + } |
897 | + |
898 | + if (!sibling && window->serverPrev) |
899 | + { |
900 | + XWindowChanges xwc; |
901 | + unsigned int valueMask = CWStackMode; |
902 | + |
903 | + xwc.stack_mode = Below; |
904 | + |
905 | + /* Below with no sibling puts the window at the bottom |
906 | + * of the stack */ |
907 | + XConfigureWindow (screen->dpy (), ROOTPARENT (window), valueMask, &xwc); |
908 | + |
909 | + if (serverFrame) |
910 | + priv->addPendingConfigure (xwc, CWStackMode); |
911 | |
912 | /* Update the list of windows last sent to the server */ |
913 | screen->unhookServerWindow (window); |
914 | @@ -5410,6 +5770,8 @@ |
915 | |
916 | if (tx || ty) |
917 | { |
918 | + unsigned int valueMask = CWX | CWY; |
919 | + XWindowChanges xwc; |
920 | int m, wx, wy; |
921 | |
922 | if (!priv->managed) |
923 | @@ -5450,10 +5812,10 @@ |
924 | if (priv->saveMask & CWY) |
925 | priv->saveWc.y += wy; |
926 | |
927 | - move (wx, wy); |
928 | + xwc.x = serverGeometry ().x () + wx; |
929 | + xwc.y = serverGeometry ().y () + wy; |
930 | |
931 | - if (sync) |
932 | - syncPosition (); |
933 | + configureXWindow (valueMask, &xwc); |
934 | } |
935 | } |
936 | |
937 | @@ -5659,18 +6021,14 @@ |
938 | if (dbg) |
939 | dbg->overrideRedirectRestack (priv->id, aboveId); |
940 | |
941 | - gettimeofday (&priv->lastGeometryUpdate, NULL); |
942 | + gettimeofday (&priv->lastConfigureRequest, NULL); |
943 | |
944 | priv->attrib = wa; |
945 | priv->serverGeometry.set (priv->attrib.x, priv->attrib.y, |
946 | priv->attrib.width, priv->attrib.height, |
947 | priv->attrib.border_width); |
948 | - priv->syncGeometry.set (priv->attrib.x, priv->attrib.y, |
949 | - priv->attrib.width, priv->attrib.height, |
950 | - priv->attrib.border_width); |
951 | - priv->geometry.set (priv->attrib.x, priv->attrib.y, |
952 | - priv->attrib.width, priv->attrib.height, |
953 | - priv->attrib.border_width); |
954 | + priv->serverFrameGeometry = priv->frameGeometry = priv->syncGeometry |
955 | + = priv->geometry = priv->serverGeometry; |
956 | |
957 | priv->width = priv->attrib.width + priv->attrib.border_width * 2; |
958 | priv->height = priv->attrib.height + priv->attrib.border_width * 2; |
959 | @@ -5982,6 +6340,7 @@ |
960 | |
961 | pendingUnmaps (0), |
962 | pendingMaps (0), |
963 | + pendingPositionUpdates (false), |
964 | |
965 | startupId (0), |
966 | resName (0), |
967 | @@ -6278,7 +6637,6 @@ |
968 | XSync (dpy, false); |
969 | return false; |
970 | } |
971 | - gettimeofday (&lastConfigureRequest, NULL); |
972 | |
973 | if (wa.override_redirect) |
974 | return false; |
975 | @@ -6309,7 +6667,7 @@ |
976 | |
977 | priv->serverGeometry.setBorder (0); |
978 | |
979 | - mask = CWBorderPixel | CWColormap | CWBackPixmap; |
980 | + mask = CWBorderPixel | CWColormap | CWBackPixmap | CWOverrideRedirect; |
981 | |
982 | if (wa.depth == 32) |
983 | { |
984 | @@ -6427,6 +6785,11 @@ |
985 | SubstructureNotifyMask | EnterWindowMask | |
986 | LeaveWindowMask; |
987 | |
988 | + serverFrameGeometry = serverGeometry; |
989 | + |
990 | + XMoveResizeWindow (dpy, serverFrame, serverFrameGeometry.x (), serverFrameGeometry.y (), |
991 | + serverFrameGeometry.width (), serverFrameGeometry.height ()); |
992 | + |
993 | XChangeWindowAttributes (dpy, serverFrame, CWEventMask, &attr); |
994 | XChangeWindowAttributes (dpy, wrapper, CWEventMask, &attr); |
995 | |
996 | @@ -6447,9 +6810,6 @@ |
997 | XUngrabServer (dpy); |
998 | XSync (dpy, false); |
999 | |
1000 | - XMoveResizeWindow (dpy, serverFrame, wa.x, wa.y, |
1001 | - wa.width, wa.height); |
1002 | - |
1003 | window->windowNotify (CompWindowNotifyReparent); |
1004 | |
1005 | return true; |
1006 | @@ -6508,6 +6868,14 @@ |
1007 | /* Wait for the reparent to finish */ |
1008 | XSync (dpy, false); |
1009 | |
1010 | + xwc.x = serverGeometry.x () - serverGeometry.border (); |
1011 | + xwc.y = serverGeometry.y () - serverGeometry.border (); |
1012 | + xwc.width = serverGeometry.width () + serverGeometry.border () * 2; |
1013 | + xwc.height = serverGeometry.height () + serverGeometry.border () * 2; |
1014 | + |
1015 | + XConfigureWindow (dpy, serverFrame, CWX | CWY | CWWidth | CWHeight, &xwc); |
1016 | + |
1017 | + |
1018 | xwc.stack_mode = Below; |
1019 | xwc.sibling = serverFrame; |
1020 | XConfigureWindow (dpy, id, CWSibling | CWStackMode, &xwc); |
+1