946 lines
23 KiB
C++
946 lines
23 KiB
C++
|
#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;
|