aboutsummaryrefslogtreecommitdiff
path: root/Src/Wasabi/api/wnd/wndtrack.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Wasabi/api/wnd/wndtrack.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Wasabi/api/wnd/wndtrack.cpp')
-rw-r--r--Src/Wasabi/api/wnd/wndtrack.cpp945
1 files changed, 945 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wnd/wndtrack.cpp b/Src/Wasabi/api/wnd/wndtrack.cpp
new file mode 100644
index 00000000..c378550e
--- /dev/null
+++ b/Src/Wasabi/api/wnd/wndtrack.cpp
@@ -0,0 +1,945 @@
+#include <precomp.h>
+#include <bfc/ptrlist.h>
+#include <api/wnd/basewnd.h>
+#include <bfc/util/findopenrect.h>
+#include <bfc/bfc_assert.h>
+#include <api/wndmgr/resize.h>
+#include <api/wnd/wndtrack.h>
+#include <api/config/items/attrint.h>
+#include <api/config/items/attrbool.h>
+#include <bfc/wasabi_std_wnd.h>
+#ifdef WASABI_COMPILE_WNDMGR
+#include <api/wndmgr/snappnt.h>
+#endif
+
+#ifdef WASABI_COMPILE_SCRIPT
+#include <api/script/scriptobj.h>
+#include <api/script/scriptguid.h>
+#include <api/wnd/wndclass/guiobjwnd.h> // for appbar define
+#endif
+
+#ifdef WASABI_COMPILE_WNDMGR
+#include <api/wndmgr/layout.h>
+#include <api/wnd/popexitcb.h>
+#endif
+
+#ifdef WASABI_COMPILE_SYSCB
+//#include <api/syscb/cbmgr.h>
+#endif
+
+WindowTracker *windowTracker;
+
+WindowTracker::WindowTracker()
+ : coopcache(0),
+ coopcachewnd(NULL)
+{
+ wascoop = 0;
+ disabledock = 0;
+ dock_enabled = 1;
+}
+
+WindowTracker::~WindowTracker()
+{
+ coopList.deleteAll();
+}
+
+void WindowTracker::addWindow(ifc_window *wnd)
+{
+ ASSERT(wnd);
+ desktopwnds.addItem(wnd);
+}
+
+void WindowTracker::removeWindow(ifc_window *wnd)
+{
+ ASSERT(wnd);
+ ASSERTPR(desktopwnds.haveItem(wnd), "removewindow on invalid wnd");
+ desktopwnds.removeItem(wnd);
+}
+
+int WindowTracker::checkWindow(ifc_window *wnd)
+{
+ return allWnd.haveItem(wnd);
+}
+
+ifc_window *WindowTracker::enumWindows(int n)
+{
+ return desktopwnds.enumItem(n);
+}
+
+ifc_window *WindowTracker::getNextDesktopWindow(ifc_window *w, int next)
+{
+ ifc_window *nw = NULL;
+ if (w == NULL) nw = desktopwnds.getFirst();
+ else
+ {
+ w = w->getDesktopParent();
+ int pos = desktopwnds.searchItem(w);
+ if (pos == -1) nw = desktopwnds.getFirst();
+ else
+ {
+ pos += next;
+ if (pos > desktopwnds.getNumItems() - 1) pos = 0;
+ if (pos == -1) pos = desktopwnds.getNumItems() - 1;
+ nw = desktopwnds.enumItem(pos);
+ }
+ }
+ if (nw == w) return w;
+ if (!nw->isVisible()) return getNextDesktopWindow(nw, next);
+ return nw;
+}
+
+ifc_window *WindowTracker::enumAllWindows(int n)
+{
+ return allWnd.enumItem(n);
+}
+
+int WindowTracker::getNumWindows()
+{
+ return desktopwnds.getNumItems();
+}
+
+int WindowTracker::getNumAllWindows()
+{
+ return allWnd.getNumItems();
+}
+
+void WindowTracker::invalidateAllWindows()
+{
+ for (int i = allWnd.getNumItems() - 1;i >= 0;i--)
+ {
+ ifc_window *w = allWnd[i];
+ w->triggerEvent(TRIGGER_INVALIDATE);
+ w->invalidate();
+ if (!w->isVirtual()) continue;
+ w->triggerEvent(TRIGGER_ONRESIZE);
+ }
+}
+
+RECT WindowTracker::findOpenRect(const RECT &prev, ifc_window *exclude)
+{
+ POINT pp = { 0, 0 };
+ //CUT if (prev != NULL) {
+ pp.x = prev.left;
+ pp.y = prev.top;
+ //CUT }
+ RECT vr; // viewport rect
+ Wasabi::Std::getViewport(&vr, &pp);
+
+ // make a rect list
+ PtrList<RECT> list;
+ for (int i = 0; ; i++)
+ {
+ ifc_window *wnd = enumWindows(i);
+ if (wnd == NULL) break;
+ if (wnd == exclude) continue;
+ if (!wnd->isPostOnInit() && !wnd->isVisible()) continue;
+ RECT *r = new RECT;
+ wnd->getWindowRect(r);
+ snapAdjustWindowRect(wnd, r);
+ list.addItem(r);
+ }
+
+ FindOpenRect fr;
+ RECT ret = fr.find(vr, list, prev);
+ list.deleteAll();
+ return ret;
+}
+
+void WindowTracker::setDockDistance(int dd)
+{
+ dockDist = MINMAX(dd, MIN_DOCK_DIST, MAX_DOCK_DIST);
+}
+
+int WindowTracker::getDockDistance()
+{
+ if (dock_enabled) return dockDist;
+ return 0;
+}
+
+void WindowTracker::setEnableDocking(int ed)
+{
+ dock_enabled = ed;
+}
+
+bool WindowTracker::touches(const RECT &r2, const RECT &r1)
+{
+ if (r2.left == r1.right || r2.right == r1.left || r2.right == r1.right || r2.left == r1.left)
+ {
+ if (r2.bottom >= r1.top && r2.top <= r1.bottom)
+ return true;
+ }
+ if (r2.top == r1.bottom || r2.bottom == r1.top || r2.bottom == r1.bottom || r2.top == r1.top)
+ {
+ if (r2.right >= r1.left && r2.left <= r1.right)
+ return true;
+ }
+ return false;
+}
+
+void WindowTracker::endCooperativeMove()
+{
+ wascoop = 1;
+ flushCoopWnds();
+ coopWnd = NULL;
+ recursList.removeAll();
+}
+
+void WindowTracker::startCooperativeMove(ifc_window *thiswnd)
+{
+ coopWnd = thiswnd;
+ wascoop = 1;
+ flushCoopWnds();
+ if (recursList.getNumItems() > 0) recursList.removeAll();
+ addCooperative(thiswnd);
+ foreach_reverse(recursList)
+ // FG> we need to prevent windows from excessively activating our windows or focus is gonna blow up
+ // thiswnd->bringToFront();
+#ifdef WIN32
+ SetWindowPos(recursList.getfor()->gethWnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_DEFERERASE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
+#else
+ recursList.getfor()->bringToFront();
+#endif
+ endfor;
+}
+
+int WindowTracker::getNumDocked()
+{
+ return recursList.getNumItems();
+}
+
+ifc_window *WindowTracker::enumDocked(int n)
+{
+ return recursList.enumItem(n);
+}
+
+void WindowTracker::addCooperative(ifc_window *thiswnd)
+{
+ int i;
+ RECT r;
+ RECT thisr;
+ bool forceall = false;
+
+ if (Std::keyModifier(STDKEY_ALT))
+ {
+ forceall = TRUE;
+ }
+
+#ifdef WASABI_COMPILE_WNDMGR
+ Layout *l = static_cast<Layout *>(thiswnd->getInterface(layoutGuid));
+ if (l)
+ {
+ for (int i = 0; i < l->getNumLockedLayouts(); i++)
+ {
+ ifc_window *wnd = l->enumLockedLayout(i);
+ addCoopWnd(wnd, 1);
+ addCooperative(wnd);
+ }
+ }
+#endif
+
+ if (recursList.searchItem(thiswnd) != -1) return ;
+
+ recursList.addItem(thiswnd);
+
+ if (Std::keyModifier(STDKEY_SHIFT)) return ;
+
+ thiswnd->getWindowRect(&thisr);
+ snapAdjustWindowRect(thiswnd, &thisr);
+
+ for (i = 0; i < desktopwnds.getNumItems(); i++)
+ {
+ ifc_window *wnd = desktopwnds.enumItem(i);
+ if (!wnd->isVisible()) continue;
+ if (hasCoopWnd(wnd)) continue;
+ if (wnd == thiswnd) continue;
+ Layout *l = (Layout*)wnd->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) continue;
+ wnd->getWindowRect(&r);
+ snapAdjustWindowRect(wnd, &r);
+
+#ifdef WASABI_COMPILE_WNDMGR
+ int snap = SnapPoint::match(thiswnd, NULL, wnd, KEEPSIZE, NULL, NULL, 0, 0);
+ if (forceall || snap || (touches(r, thisr) && !Wasabi::Std::rectIntersect(r, thisr)))
+ {
+#else
+ if (forceall || (touches(r, thisr) && !Std::rectIntersect(r, thisr)))
+ {
+#endif
+ addCoopWnd(wnd);
+ addCooperative(wnd);
+ }
+ }
+}
+
+bool WindowTracker::autoDock(ifc_window *thishWnd, RECT *newPosition, int mask)
+{
+ return autoDock(thishWnd, newPosition, NULL, mask);
+}
+
+bool WindowTracker::autoDock(ifc_window *thiswnd, RECT *z, RECT *_oldPosition, int mask)
+{
+ int i = 0;
+ RECT r = {0};
+#ifdef WASABI_COMPILE_CONFIG
+ extern _bool cfg_options_docking;
+ extern _int cfg_options_dockingdistance;
+
+ dockDist = cfg_options_dockingdistance;
+ dock_enabled = cfg_options_docking;
+#else
+#warning check these values
+ dockDist = 4;
+ dock_enabled = 4;
+#endif
+
+#ifdef USEAPPBAR
+ // Layout *_l = static_cast<Layout *>(thiswnd->getInterface(layoutGuid));
+ // if (_l->appbar_isDocked()) return 0;
+#endif
+
+ RECT z_snapAdjust = {0};
+ snapAdjustWindowRect(thiswnd, z, &z_snapAdjust);
+ RECT *oldPosition = _oldPosition;
+ if (oldPosition)
+ {
+ oldPosition->left += z_snapAdjust.left;
+ oldPosition->top += z_snapAdjust.top;
+ }
+
+ if (!coopWnd)
+ wascoop = 0;
+
+ disabledock = 0;
+
+ if (Std::keyModifier(STDKEY_SHIFT))
+ {
+ for (int i = 0;i < coopList.getNumItems();i++)
+ {
+ coopEntry *e = coopList.enumItem(i);
+ if (!e->locked)
+ {
+ delete e;
+ coopList.removeByPos(i);
+ coopcachewnd = NULL;
+ i--;
+ }
+ }
+ disabledock = 1;
+ }
+
+ int f = 0, s = 0;
+ int w = z->right - z->left;
+ int h = z->bottom - z->top;
+
+ POINT done = {0};
+
+ if (!disabledock)
+ {
+ ifc_window *wnd = NULL;
+ for (i = desktopwnds.getNumItems(); i > -1; i--)
+ {
+ if (i == desktopwnds.getNumItems())
+ {
+#ifdef USEAPPBAR
+ Layout *l = static_cast<Layout *>(thiswnd->getInterface(layoutGuid));
+ if (l->appbar_isDocked()) continue;
+#endif
+ Wasabi::Std::getViewport(&r, thiswnd->gethWnd());
+ wnd = NULL;
+ }
+ else
+ {
+ wnd = desktopwnds.enumItem(i);
+ if (coopWnd != NULL && hasCoopWnd(wnd)) continue;
+ Layout *l = (Layout*)wnd->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) continue;
+
+ if (wnd->isVisible())
+ {
+ wnd->getWindowRect(&r);
+ snapAdjustWindowRect(wnd, &r);
+ }
+ else continue;
+ }
+
+ if (coopWnd != NULL && coopWnd == wnd || (i >= 0 && hasCoopWnd(desktopwnds.enumItem(i)))) continue;
+
+ if (thiswnd == wnd) continue;
+
+ RECT oz = *z;
+ POINT thisdone = {0};
+
+#ifdef WASABI_COMPILE_WNDMGR
+ if (SnapPoint::match(thiswnd, z, wnd, mask, (int *)&thisdone.x, (int *)&thisdone.y, w, h)) s++;
+#endif
+ if (z->left > r.left - getDockDistance() && z->left < r.left + getDockDistance() && (mask & LEFT) && !thisdone.x)
+ {
+ z->left = r.left;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->right = r.left + w;
+ f++;
+ }
+ if (i != desktopwnds.getNumItems() && z->right > r.left - getDockDistance() && z->right < r.left + getDockDistance() && (mask & RIGHT) && !thisdone.x)
+ {
+ z->right = r.left;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->left = r.left - w;
+ f++;
+ }
+ if (z->top > r.top - getDockDistance() && z->top < r.top + getDockDistance() && (mask & TOP) && !thisdone.y)
+ {
+ z->top = r.top;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->bottom = r.top + h;
+ f++;
+ }
+ if (i != desktopwnds.getNumItems() && z->bottom > r.top - getDockDistance() && z->bottom < r.top + getDockDistance() && (mask & BOTTOM) && !thisdone.y)
+ {
+ z->bottom = r.top;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->top = r.top - h;
+ f++;
+ }
+ if (z->right > r.right - getDockDistance() && z->right < r.right + getDockDistance() && (mask & RIGHT) && !thisdone.x)
+ {
+ z->right = r.right;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->left = r.right - w;
+ f++;
+ }
+ if (i != desktopwnds.getNumItems() && z->left > r.right - getDockDistance() && z->left < r.right + getDockDistance() && (mask & LEFT) && !thisdone.x)
+ {
+ z->left = r.right;
+ thisdone.x = 1;
+ if (mask & KEEPSIZE) z->right = r.right + w;
+ f++;
+ }
+
+ if (z->bottom > r.bottom - getDockDistance() && z->bottom < r.bottom + getDockDistance() && (mask & BOTTOM) && !thisdone.y)
+ {
+ z->bottom = r.bottom;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->top = r.bottom - h;
+ f++;
+ }
+
+ if (i != desktopwnds.getNumItems() && z->top > r.bottom - getDockDistance() && z->top < r.bottom + getDockDistance() && (mask & TOP) && !thisdone.y)
+ {
+ z->top = r.bottom;
+ thisdone.y = 1;
+ if (mask & KEEPSIZE) z->bottom = r.bottom + h;
+ f++;
+ }
+
+ if (((wnd != NULL && (mask & NOINTERSECT) && Wasabi::Std::rectIntersect(*z, r)) || !touches(*z, r)) && !s)
+ {
+ *z = oz;
+ thisdone.x = 0;
+ thisdone.y = 0;
+ }
+
+ done.x |= thisdone.x;
+ done.y |= thisdone.y;
+ }
+ }
+
+ if (coopWnd == thiswnd && oldPosition)
+ {
+ POINT s = {0}, redock = {0};
+ TList<RECT> rlist;
+ s.x = z->left - oldPosition->left;
+ s.y = z->top - oldPosition->top;
+ for (i = 0;i < coopList.getNumItems();i++)
+ {
+ RECT r = {0};
+ ifc_window *W = coopList.enumItem(i)->wnd;
+ if (!checkWindow(W)) { coopEntry *e = coopList.enumItem(i); delete e; coopList.removeByPos(i); i--; continue; }
+ if (W != (BaseWnd*) - 1)
+ {
+ W->getWindowRect(&r);
+ //snapAdjustWindowRect(W, &r);
+ }
+#ifdef WIN32
+ else
+ GetWindowRect(WASABI_API_WND->main_getRootWnd()->gethWnd(), &r);
+#endif
+ int w = r.right - r.left, h = r.bottom - r.top;
+ r.left += s.x;
+ r.top += s.y;
+ r.right = r.left + w;
+ r.bottom = r.top + h;
+ RECT cr = r;
+ if (autoDock(W, &cr, LEFT | RIGHT | TOP | BOTTOM | NOINTERSECT | KEEPSIZE))
+ {
+ if (redock.x == 0) redock.x = cr.left - r.left;
+ if (redock.y == 0) redock.y = cr.top - r.top;
+ }
+ rlist.addItem(r);
+ }
+
+ if (redock.x || redock.y)
+ {
+ Wasabi::Std::offsetRect(z, redock.x, redock.y);
+ f++;
+ }
+#ifdef WIN32
+ HDWP hd = NULL;
+ if (coopList.getNumItems() > 0) hd = BeginDeferWindowPos(coopList.getNumItems());
+#endif
+ for (i = 0;i < coopList.getNumItems();i++)
+ {
+ RECT r = rlist.enumItem(i);
+ ifc_window *W = coopList.enumItem(i)->wnd;
+ r.left += redock.x;
+ r.top += redock.y;
+ //unsnapAdjustWindowRect(W, &r);
+#ifdef WIN32
+ W->notifyDeferredMove(r.left, r.top);
+ //if (GetWindow(W->gethWnd(), GW_OWNER))
+// SetWindowPos(W->gethWnd(), NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+// else
+ hd = DeferWindowPos(hd, W->gethWnd(), NULL, r.left, r.top, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
+#else
+ W->move( r.left, r.top );
+#endif
+ }
+ foreach(coopList)
+ ifc_window *w = coopList.getfor()->wnd;
+ if (w != coopWnd)
+ {
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l)
+ {
+ l->beginMove();
+ }
+ }
+ endfor;
+#ifdef WIN32
+ if (coopList.getNumItems() > 0) EndDeferWindowPos(hd);
+#endif
+ foreach(coopList)
+ ifc_window *w = coopList.getfor()->wnd;
+ if (w != coopWnd)
+ {
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l)
+ {
+ l->onMove();
+ l->endMove();
+ }
+ }
+ endfor;
+ rlist.removeAll();
+ }
+
+ z->left -= z_snapAdjust.left;
+ z->top -= z_snapAdjust.top;
+ z->right += z_snapAdjust.right;
+ z->bottom += z_snapAdjust.bottom;
+
+ return ((f + s) != 0);
+}
+
+int WindowTracker::hasCoopWnd(ifc_window *w)
+{
+ if (coopcachewnd == w) return coopcache;
+ coopcachewnd = w;
+ coopcache = 0;
+ for (int i = 0;i < coopList.getNumItems();i++)
+ if (coopList.enumItem(i)->wnd == w)
+ {
+ coopcache = 1;
+ break;
+ }
+ return coopcache;
+}
+
+void WindowTracker::addCoopWnd(ifc_window *w, int forced)
+{
+ coopList.addItem(new coopEntry(w, forced));
+ coopcachewnd = NULL;
+}
+
+void WindowTracker::flushCoopWnds()
+{
+ coopList.deleteAll();
+ coopcachewnd = NULL;
+}
+
+void WindowTracker::addRootWnd(ifc_window *wnd)
+{
+ ASSERT(!allWnd.haveItem(wnd));
+ allWnd.addItem(wnd);
+ if (!wnd->isVirtual())
+ {
+ ASSERT(!nonvirtuals.haveItem(wnd));
+ nonvirtuals.addItem(wnd);
+ }
+}
+
+void WindowTracker::removeRootWnd(ifc_window *wnd)
+{
+ allWnd.delItem(wnd);
+ if (allWnd.getNumItems() == 0) allWnd.deleteAll(); // avoid fortify fals alarm on static
+ int n = nonvirtuals.searchItem(wnd);
+ if (n > -1) nonvirtuals.removeByPos(n);
+}
+
+ifc_window *WindowTracker::rootWndFromPoint(POINT *pt)
+{
+ /* api_window *last = NULL;
+ api_window *last_parent = NULL;
+ for (int i=0;i<allWnd.getNumItems();i++) {
+ api_window *w = allWnd[i];
+ if (last && w->getRootWndParent() != last_parent)
+ return checkGhost(last, (signed short)pt->x, (signed short)pt->y);
+ if (w->pointInWnd(pt)) {
+ if (!w->getRootWndParent() || w->gethWnd() != w->getRootWndParent()->gethWnd()) return checkGhost(w, (signed short)pt->x, (signed short)pt->y);
+ last = w;
+ last_parent = w->getRootWndParent();
+ }
+ }
+ return NULL;*/
+
+ // Get window's top level window for pt
+#ifdef _WIN32
+ OSWINDOWHANDLE t = WindowFromPoint(*pt);
+ if (!t) return NULL;
+
+ //CHECK IF SAFE ! if (!rootWndFromHwnd(t)) return NULL;
+
+ // Find its rootWnd
+ for (int i = nonvirtuals.getNumItems() - 1;i >= 0;i--)
+ {
+ ifc_window *r = nonvirtuals[i];
+ if (r->gethWnd() == t)
+ {
+ POINT p = *pt;
+ r->screenToClient((int*)&p.x, (int *)&p.y);
+ return r->findRootWndChild(p.x, p.y);
+ }
+ }
+#else
+#warning port me!
+#endif
+ return NULL;
+}
+
+ifc_window *WindowTracker::rootWndFromHwnd(OSWINDOWHANDLE h)
+{
+ if (!h) return NULL;
+ // Find its rootWnd
+ for (int i = 0;i < allWnd.getNumItems();i++)
+ {
+ ifc_window *r = allWnd[i];
+ if (r->gethWnd() == h) return r;
+ }
+ return NULL;
+}
+
+int WindowTracker::wasCooperativeMove()
+{
+ return wascoop;
+}
+
+// TODO: can be moved to a static function - doesn't seem to use any class data
+void WindowTracker::snapAdjustWindowRect(ifc_window *w, RECT *r, RECT *adjustvals)
+{
+#ifdef WASABI_COMPILE_WNDMGR
+ if (w->getInterface(layoutGuid))
+ {
+ RECT snapAdjust = {0};
+ static_cast<Layout *>(w)->getSnapAdjust(&snapAdjust);
+ double rr = w->getRenderRatio();
+ if (rr != 1.0)
+ {
+ snapAdjust.left = (int)((double)(snapAdjust.left) * rr);
+ snapAdjust.top = (int)((double)(snapAdjust.top) * rr);
+ snapAdjust.right = (int)((double)(snapAdjust.right) * rr);
+ snapAdjust.bottom = (int)((double)(snapAdjust.bottom) * rr);
+ }
+ r->left += snapAdjust.left;
+ r->top += snapAdjust.top;
+ r->right -= snapAdjust.right;
+ r->bottom -= snapAdjust.bottom;
+ if (adjustvals) *adjustvals = snapAdjust;
+ }
+ else { adjustvals = NULL; }
+#else
+ if (adjustvals) MEMSET(adjustvals, 0, sizeof(RECT));
+#endif
+}
+
+void WindowTracker::unsnapAdjustWindowRect(ifc_window *w, RECT *r, RECT *adjustvals)
+{
+#ifdef WASABI_COMPILE_WNDMGR
+ if (w->getInterface(layoutGuid))
+ {
+ RECT snapAdjust = {0};
+ static_cast<Layout *>(w)->getSnapAdjust(&snapAdjust);
+ if (w->getRenderRatio() != 1.0)
+ {
+ double rr = w->getRenderRatio();
+ snapAdjust.left = (int)((double)(snapAdjust.left) * rr);
+ snapAdjust.top = (int)((double)(snapAdjust.top) * rr);
+ snapAdjust.right = (int)((double)(snapAdjust.right) * rr);
+ snapAdjust.bottom = (int)((double)(snapAdjust.bottom) * rr);
+ }
+ r->left -= snapAdjust.left;
+ r->top -= snapAdjust.top;
+ r->right += snapAdjust.right;
+ r->bottom += snapAdjust.bottom;
+ if (adjustvals) *adjustvals = snapAdjust;
+ }
+ else { adjustvals = NULL; }
+#else
+ if (adjustvals) MEMSET(adjustvals, 0, sizeof(RECT));
+#endif
+}
+
+void WindowTracker::recursAddToMoveWindows(ifc_window *wnd, redock_struct *rs, int v)
+{
+ if (!rs) return ;
+ RECT r1;
+ if (wnd != NULL)
+ {
+ wnd->getWindowRect(&r1);
+ snapAdjustWindowRect(wnd, &r1);
+ }
+ else
+ {
+ wnd = rs->l;
+ r1 = rs->original_rect;
+ if (!WASABI_API_WND->rootwndIsValid(wnd)) return ;
+ }
+
+ {
+ Layout *l = (Layout*)wnd->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) return ;
+ }
+
+ // add all touching windows
+ for (int i = 0; i < desktopwnds.getNumItems(); i++)
+ {
+ ifc_window *w = desktopwnds[i];
+ if (!w->isVisible()) continue;
+ if (w == wnd) continue;
+ Layout *l = (Layout*)w->getInterface(layoutGuid);
+ if (l && (l->getNoDock()
+#ifdef USEAPPBAR
+ || l->appbar_isDocked()
+#endif
+ )) continue;
+ RECT r2;
+ w->getWindowRect(&r2);
+ snapAdjustWindowRect(w, &r2);
+ // check for bottom touch
+ if ((v == 1 || v == -1) && r2.top == r1.bottom && !tomoveWindows_bottom.haveItem(w))
+ {
+ if (r2.right >= r1.left && r2.left <= r1.right)
+ {
+ tomoveWindows_bottom.addItem(w);
+ recursAddToMoveWindows(w, rs, 1);
+ }
+ }
+ // check for right touch
+ if ((v == 0 || v == -1) && r2.left == r1.right && !tomoveWindows_right.haveItem(w))
+ {
+ if (r2.bottom >= r1.top && r2.top <= r1.bottom)
+ {
+ tomoveWindows_right.addItem(w);
+ recursAddToMoveWindows(w, rs, 0);
+ }
+ }
+ // check for left touch
+ if ((v == 0 || v == -1) && r2.right == r1.left && !tomoveWindows_left.haveItem(w))
+ {
+ if (r2.bottom >= r1.top && r2.top <= r1.bottom)
+ {
+ tomoveWindows_left.addItem(w);
+ recursAddToMoveWindows(w, rs, 0);
+ }
+ }
+ // check for top touch
+ if ((v == 1 || v == -1) && r2.bottom == r1.top && !tomoveWindows_top.haveItem(w))
+ {
+ if (r2.right >= r1.left && r2.left <= r1.right)
+ {
+ tomoveWindows_top.addItem(w);
+ recursAddToMoveWindows(w, rs, 1);
+ }
+ }
+ }
+}
+
+void WindowTracker::beforeRedock(Layout *l, redock_struct *rs)
+{
+ if (!l) return ;
+ rs->l = l;
+ l->getWindowRect(&rs->original_rect);
+ snapAdjustWindowRect(rs->l, &rs->original_rect);
+}
+
+void WindowTracker::afterRedock(Layout *l, redock_struct *rs)
+{
+ RECT nr;
+ if (!rs) return ;
+
+ if (!WASABI_API_WND->rootwndIsValid(l)) return ;
+ if (!WASABI_API_WND->rootwndIsValid(rs->l)) return ;
+ recursAddToMoveWindows(NULL, rs);
+
+ l->getWindowRect(&nr);
+ snapAdjustWindowRect(l, &nr);
+
+ if (l->isUnlinked() || rs->l->isUnlinked()) return ;
+
+#ifdef WIN32
+ HDWP hdwp = BeginDeferWindowPos(desktopwnds.getNumItems());
+#endif
+
+ PtrList<Layout> toendmove;
+
+ int diff = rs->original_rect.bottom - nr.bottom;
+ if (diff)
+ { // check for bottom side dock changes
+ for (int i = 0;i < tomoveWindows_bottom.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_bottom[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.top -= diff;
+ r.bottom -= diff;
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+ diff = rs->original_rect.top - nr.top;
+ if (diff)
+ { // check for top side dock changes
+ for (int i = 0;i < tomoveWindows_top.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_top[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.top -= diff;
+ r.bottom -= diff;
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+ diff = rs->original_rect.right - nr.right;
+ if (diff)
+ { // check for right side dock changes
+ for (int i = 0;i < tomoveWindows_right.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_right[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.left -= diff;
+ r.right -= diff;
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) l->beginMove();
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+ diff = rs->original_rect.left - nr.left;
+ if (diff)
+ { // check for left side dock changes
+ for (int i = 0;i < tomoveWindows_left.getNumItems();i++)
+ {
+ ifc_window *w = tomoveWindows_left[i];
+ if (w == l) continue;
+ if (w == rs->l) continue;
+ if (!allWnd.haveItem(w)) continue;
+ RECT r;
+ w->getWindowRect(&r);
+ r.left -= diff;
+ r.right -= diff;
+ Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid));
+ if (l) l->beginMove();
+#ifdef WIN32
+ w->notifyDeferredMove(r.left, r.top);
+ DeferWindowPos(hdwp, w->gethWnd(), NULL, r.left, r.top, r.right - r.left, r.bottom - r.top, SWP_NOZORDER | SWP_NOACTIVATE);
+#else
+ w->move( r.left, r.top );
+#endif
+ if (l) toendmove.addItem(l);
+ }
+ }
+
+#ifdef WIN32
+ EndDeferWindowPos(hdwp);
+#endif
+ tomoveWindows_left.removeAll();
+ tomoveWindows_top.removeAll();
+ tomoveWindows_right.removeAll();
+ tomoveWindows_bottom.removeAll();
+ rs->l = NULL;
+ foreach(toendmove)
+ toendmove.getfor()->onMove();
+ toendmove.getfor()->endMove();
+ endfor;
+}
+
+void WindowTracker::layoutChanged(Layout *previouswnd, Layout *newwnd)
+{
+ redock_struct rs;
+ beforeRedock(previouswnd, &rs);
+ afterRedock(newwnd, &rs);
+}
+
+ifc_window *WindowTracker::coopWnd = NULL;
+PtrList<ifc_window> WindowTracker::desktopwnds;
+PtrList<ifc_window> WindowTracker::nonvirtuals;
+PtrList<coopEntry> WindowTracker::coopList;
+PtrList<ifc_window> WindowTracker::recursList;
+PtrList<ifc_window> WindowTracker::tomoveWindows_left;
+PtrList<ifc_window> WindowTracker::tomoveWindows_top;
+PtrList<ifc_window> WindowTracker::tomoveWindows_right;
+PtrList<ifc_window> WindowTracker::tomoveWindows_bottom;
+PtrList<ifc_window> WindowTracker::allWnd;
+int WindowTracker::dockDist = DEFAULT_DOCK_DIST;
+int WindowTracker::dock_enabled = 1;