The diff is big and scary, but its not too complicated. I'll explain each separate part 1 === modified file 'include/core/window.h' 2 --- include/core/window.h 2012-01-20 15:20:44 +0000 3 +++ include/core/window.h 2012-01-31 17:12:59 +0000 4 @@ -398,9 +398,9 @@ 5 6 bool hasUnmapReference (); 7 8 - bool resize (XWindowAttributes); 9 + bool resize (const XWindowAttributes &); 10 11 - bool resize (Geometry); 12 + bool resize (const Geometry &); 13 14 bool resize (int x, int y, int width, int height, 15 int border = 0); const correctness 31 int x1, x2, y1, y2; 32 33 - CompWindow::Geometry geom = priv->window->geometry (); 34 - CompWindowExtents output = priv->window->output (); 35 + const CompWindow::Geometry &geom = priv->window->serverGeometry (); 36 + const CompWindowExtents &output = priv->window->output (); more const correctness 35 + const CompWindow::Geometry &geom = priv->window->serverGeometry (); 36 + const CompWindowExtents &output = priv->window->output (); Lots of this - in paint code we want to use serverFoo because it was the last thing sent to the server. And this is always guarunteed to come back to us. 166 - unsigned int width = window->size ().width (); 167 - unsigned int height = window->size ().height (); 168 + unsigned int width = window->geometry ().width (); 169 + unsigned int height = window->geometry ().height (); CompWindow::size was just returning CompSize (priv->width, priv->height) which was just redundant data which should be removed. Replaced it with geometry () for clarity 299 + void move (int dx, int dy, bool sync); 300 + bool resize (int dx, int dy, int dwidth, int dheight, int dborder); 301 + bool resize (const CompWindow::Geometry &g); 302 + bool resize (const XWindowAttributes &attrib); 303 + Added PrivateWindow::move and PrivateWindow::resize - to be called whenever a new position / size comes back from the server. (cut'n'paste code from CompWindow::move and CompWindow::resize 335 - 336 - gettimeofday (&lastConfigureRequest, NULL); 337 - /* Flush any changes made to serverFrameGeometry or serverGeometry to the server 338 - * since there is a race condition where geometries will go out-of-sync with 339 - * window movement */ 340 - 341 - window->syncPosition (); 342 - 343 - if (serverInput.left || serverInput.right || serverInput.top || serverInput.bottom) 344 - { 345 - int bw = serverGeometry.border () * 2; 346 - 347 - xwc.x = serverGeometry.x () - serverInput.left; 348 - xwc.y = serverGeometry.y () - serverInput.top; 349 - xwc.width = serverGeometry.width () + serverInput.left + serverInput.right + bw; 350 - if (shaded) 351 - xwc.height = serverInput.top + serverInput.bottom + bw; 352 - else 353 - xwc.height = serverGeometry.height () + serverInput.top + serverInput.bottom + bw; 354 - 355 - if (shaded) 356 - height = serverInput.top + serverInput.bottom; 357 - 358 - if (serverFrameGeometry.x () == xwc.x) 359 - valueMask &= ~(CWX); 360 - else 361 - serverFrameGeometry.setX (xwc.x); 362 - *snip* 616 - XMoveResizeWindow (screen->dpy (), id, 0, 0, 617 - serverGeometry.width (), serverGeometry.height ()); 618 - window->sendConfigureNotify (); 619 - window->windowNotify (CompWindowNotifyFrameUpdate); 620 - } 621 + xwc.x = serverGeometry.x (); 622 + xwc.y = serverGeometry.y (); 623 + xwc.width = serverGeometry.width (); 624 + xwc.height = serverGeometry.height (); 625 + xwc.border_width = serverGeometry.border (); 626 + 627 + window->configureXWindow (valueMask, &xwc); 628 + window->windowNotify (CompWindowNotifyFrameUpdate); All of this was just redundant code, which was already duplicated by configureXWindow (the synthetic event code was moved into configureXWindow) 704 + if (priv->attrib.override_redirect) 705 + { 706 + priv->serverGeometry = priv->geometry; 707 + priv->serverFrameGeometry = priv->frameGeometry; 708 + } For override redirect windows we must always update the "geometry last sent to server" whenever a new geometry comes through since we never update this ourselves 718 else if (priv->geometry.x () != gm.x () || priv->geometry.y () != gm.y ()) 719 { 720 - int dx, dy; 721 - 722 - dx = gm.x () - priv->geometry.x (); 723 - dy = gm.y () - priv->geometry.y (); 724 - 725 - priv->geometry.setX (gm.x ()); 726 - priv->geometry.setY (gm.y ()); 727 - 728 - priv->region.translate (dx, dy); 729 - priv->inputRegion.translate (dx, dy); 730 - if (!priv->frameRegion.isEmpty ()) 731 - priv->frameRegion.translate (dx, dy); 732 - 733 - priv->invisible = WINDOW_INVISIBLE (priv); 734 - 735 - moveNotify (dx, dy, true); 736 + move (gm.x () - priv->geometry.x (), 737 + gm.y () - priv->geometry.y (), true); 738 } 739 740 - updateFrameRegion (); 741 + window->updateFrameRegion (); 742 + 743 + return true; 744 +} All of this code was redundant - just call PrivateWindow::move whenever the position changes 890 - gettimeofday (&priv->lastConfigureRequest, NULL); 891 - 892 - unsigned int valueMask = CWX | CWY; 893 - XWindowChanges xwc = XWINDOWCHANGES_INIT; 894 - 895 - if (priv->pendingPositionUpdates && !priv->pendingConfigures.pending ()) 896 - { 897 - if (priv->serverFrameGeometry.x () == priv->frameGeometry.x ()) 898 - valueMask &= ~(CWX); 899 - if (priv->serverFrameGeometry.y () == priv->frameGeometry.y ()) 900 - valueMask &= ~(CWY); 901 - 902 - /* Because CompWindow::move can update the geometry last 903 - * received from the server, we must indicate that no values 904 - * changed, because when the ConfigureNotify comes around 905 - * the values are going to be the same. That's obviously 906 - * broken behaviour and worthy of a FIXME, but requires 907 - * larger changes to the window movement system. */ 908 - if (valueMask) 909 - { 910 - priv->serverGeometry.setX (priv->geometry.x ()); 911 - priv->serverGeometry.setY (priv->geometry.y ()); 912 - priv->serverFrameGeometry.setX (priv->frameGeometry.x ()); 913 - priv->serverFrameGeometry.setY (priv->frameGeometry.y ()); 914 - 915 - xwc.x = priv->serverFrameGeometry.x (); 916 - xwc.y = priv->serverFrameGeometry.y (); 917 - 918 - compiz::X11::PendingEvent::Ptr pc = 919 - boost::shared_static_cast (compiz::X11::PendingConfigureEvent::Ptr ( 920 - new compiz::X11::PendingConfigureEvent ( 921 - screen->dpy (), priv->serverFrame, 0, &xwc))); 922 - 923 - priv->pendingConfigures.add (pc); 924 - 925 - /* Got 3 seconds to get its stuff together */ 926 - if (priv->mClearCheckTimeout.active ()) 927 - priv->mClearCheckTimeout.stop (); 928 - priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv), 929 - 2000, 2500); 930 - XConfigureWindow (screen->dpy (), ROOTPARENT (this), valueMask, &xwc); 931 - 932 - if (priv->serverFrame) 933 - { 934 - XMoveWindow (screen->dpy (), priv->wrapper, 935 - priv->serverInput.left, priv->serverInput.top); 936 - sendConfigureNotify (); 937 - } 938 - } 939 - priv->pendingPositionUpdates = false; 940 - } DIE 1092 @@ -3692,6 +3473,9 @@ 1093 CompWindow::configureXWindow (unsigned int valueMask, 1094 XWindowChanges *xwc) 1095 { 1096 + int dx = valueMask & CWX ? xwc->x - priv->serverGeometry.x () : 0; 1097 + int dy = valueMask & CWY ? xwc->y - priv->serverGeometry.y () : 0; 1098 + 1099 if (priv->managed && (valueMask & (CWSibling | CWStackMode))) 1100 { 1101 CompWindowList transients; 1102 @@ -3746,6 +3530,17 @@ 1103 { 1104 priv->reconfigureXWindow (valueMask, xwc); 1105 } 1106 + 1107 + if (!overrideRedirect () && (dx || dy)) 1108 + { 1109 + priv->region.translate (dx, dy); 1110 + priv->inputRegion.translate (dx, dy); 1111 + if (!priv->frameRegion.isEmpty ()) 1112 + priv->frameRegion.translate (dx, dy); 1113 + moveNotify (dx, dy, priv->nextMoveImmediate); 1114 + 1115 + priv->nextMoveImmediate = true; 1116 + } Always update the window region and call moveNotify when a new position is sent to the server for a managed window, nextMoveImmediate is because I can't break the configureXWindow API 1011 + else 1012 + { 1013 + /* Craft an XConfigureWindow event to send to the frame window */ 1014 + XConfigureEvent xev; 1015 + XWindowAttributes attrib; 1016 + unsigned int nchildren = 0; 1017 + Window rootRet = 0, parentRet = 0; 1018 + Window *children = NULL; 1019 + 1020 + XWindowChanges wc = *xwc; 1021 + 1022 + wc.x = serverFrameGeometry.x (); 1023 + wc.y = serverFrameGeometry.y (); 1024 + wc.width = serverFrameGeometry.width (); 1025 + wc.height = serverFrameGeometry.height (); 1026 + 1027 + xev.type = ConfigureNotify; 1028 + xev.event = screen->root (); 1029 + xev.window = priv->serverFrame; 1030 + 1031 + XGrabServer (screen->dpy ()); 1032 + 1033 + if (XGetWindowAttributes (screen->dpy (), priv->serverFrame, &attrib)) 1034 + { 1035 + xev.x = attrib.x; 1036 + xev.y = attrib.y; 1037 + xev.width = attrib.width; 1038 + xev.height = attrib.height; 1039 + xev.border_width = attrib.border_width; 1040 + xev.above = None; 1041 + 1042 + /* We need to ensure that the stacking order is 1043 + * based on the current server stacking order so 1044 + * find the sibling to this window's frame in the 1045 + * server side stack and stack above that */ 1046 + XQueryTree (screen->dpy (), screen->root (), &rootRet, &parentRet, &children, &nchildren); 1047 + 1048 + if (nchildren) 1049 + { 1050 + for (unsigned int i = 0; i < nchildren; i++) 1051 + { 1052 + if (i + 1 == nchildren || 1053 + children[i + 1] == ROOTPARENT (window)) 1054 + { 1055 + xev.above = children[i]; 1056 + break; 1057 + } 1058 + } 1059 + } 1060 + 1061 + if (children) 1062 + XFree (children); 1063 + 1064 + if (!xev.above) 1065 + xev.above = (window->serverPrev) ? ROOTPARENT (window->serverPrev) : None; 1066 + 1067 + xev.override_redirect = priv->attrib.override_redirect; 1068 + 1069 + } 1070 + 1071 + compiz::X11::PendingEvent::Ptr pc = 1072 + boost::shared_static_cast (compiz::X11::PendingConfigureEvent::Ptr ( 1073 + new compiz::X11::PendingConfigureEvent ( 1074 + screen->dpy (), serverFrame, valueMask, &wc))); 1075 + 1076 + pendingConfigures.add (pc); 1077 + if (priv->mClearCheckTimeout.active ()) 1078 + priv->mClearCheckTimeout.stop (); 1079 + priv->mClearCheckTimeout.start (boost::bind (&PrivateWindow::checkClear, priv), 1080 + 2000, 2500); 1081 + 1082 + XSendEvent (screen->dpy (), screen->root (), false, 1083 + SubstructureNotifyMask, (XEvent *) &xev); 1084 + 1085 + XUngrabServer (screen->dpy ()); 1086 + XSync (screen->dpy (), false); 1087 + } This block is copypasted from updateFrameWindow. Its scary looking but all it does is send a ConfigureWindow request to the target window using the most uptodate information from the server