diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Wasabi/api/wndmgr/skinembed.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Wasabi/api/wndmgr/skinembed.cpp')
-rw-r--r-- | Src/Wasabi/api/wndmgr/skinembed.cpp | 733 |
1 files changed, 733 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wndmgr/skinembed.cpp b/Src/Wasabi/api/wndmgr/skinembed.cpp new file mode 100644 index 00000000..079bc688 --- /dev/null +++ b/Src/Wasabi/api/wndmgr/skinembed.cpp @@ -0,0 +1,733 @@ +#include <precomp.h> +#include "skinembed.h" +#include <api/wndmgr/layout.h> +#include <api/wnd/wndclass/wndholder.h> +#include <api/skin/skinparse.h> +#include <api/wnd/wndtrack.h> +#include <api/config/items/cfgitemi.h> +#include <api/config/items/attrint.h> +#include <bfc/named.h> +#include <api/wndmgr/autopopup.h> +#include <api/syscb/callbacks/wndcb.h> +#include <api/wndmgr/skinwnd.h> +#include <api/script/scriptmgr.h> +#include <bfc/critsec.h> + +CriticalSection skinembed_cs; + +SkinEmbedder *skinEmbedder = NULL; + +SkinEmbedder::SkinEmbedder() +{ + ASSERTPR(skinEmbedder == NULL, "only one skin embedder please!"); + skinEmbedder = this; +} + +SkinEmbedder::~SkinEmbedder() +{ + inserted.deleteAll(); + allofthem.deleteAll(); +} + +int SkinEmbedder::toggle(GUID g, const wchar_t *prefered_container, int container_flag, RECT *r, int transcient) +{ + ifc_window *w = enumItem(g, 0); + if (w != NULL) + { + destroy(w, r); + return 0; + } + ifc_window *wnd = create(g, NULL, prefered_container, container_flag, r, transcient); + if (wnd == NULL) + { +#ifdef ON_CREATE_EXTERNAL_WINDOW_GUID + int y; + ON_CREATE_EXTERNAL_WINDOW_GUID(g, y); +#endif + + } + return 1; +} + +int SkinEmbedder::toggle(const wchar_t *groupid, const wchar_t *prefered_container, int container_flag, RECT *r, int transcient) +{ + ifc_window *w = enumItem(groupid, 0); + if (w != NULL) + { + destroy(w, r); + return 0; + } + create(INVALID_GUID, groupid, prefered_container, container_flag, r, transcient); + return 1; +} + +ifc_window *SkinEmbedder::create(GUID g, const wchar_t *prefered_container, int container_flag, RECT *r, int transcient, int starthidden, int *isnew) +{ + return create(g, NULL, prefered_container, container_flag, r, transcient, starthidden, isnew); +} + +ifc_window *SkinEmbedder::create(const wchar_t *groupid, const wchar_t *prefered_container, int container_flag, RECT *r, int transcient, int starthidden, int *isnew) +{ + return create(INVALID_GUID, groupid, prefered_container, container_flag, r, transcient, starthidden, isnew); +} + +WindowHolder *SkinEmbedder::getSuitableWindowHolder(GUID g, const wchar_t *group_id, Container *cont, Layout *lay, int _visible, int _dynamic, int _empty, int _hasself, int _autoavail) +{ + foreach(wndholders) + WindowHolder *h = wndholders.getfor(); + + ifc_window *w = h->getRootWndPtr()->getDesktopParent(); + int dyn = 1; + int visible = 0; + int hasself = 0; + int empty = 0; + int autoavail = h->wndholder_isAutoAvailable(); + + Layout *l = (NULL != w) ? static_cast<Layout *>(w->getInterface(layoutGuid)) : NULL; + Container *c = NULL; + + if (l) + { + c = l->getParentContainer(); + if (c) + { + dyn = c->isDynamic(); + } + } + + if (NULL == w || !w->isInited()) visible = -1; + else + { + if (_visible == 1) + { + if (h->getRootWndPtr()->isVisible()) visible = 1; + } + else if (_visible == 0) + { + if (w->isVisible()) visible = 1; + } + } + if (!h->getCurRootWnd()) empty = 1; + + if (g != INVALID_GUID) + { + if (g == h->getCurGuid()) + hasself = 1; + } + else if (group_id && h->getCurGroupId()) + { + if (!WCSICMP(group_id, h->getCurGroupId())) + hasself = 1; + } + + if (_visible != -1) + { + if (visible != _visible) continue; + } + if (_dynamic != -1) + { + if (_dynamic != dyn) continue; + } + if (_empty != -1) + { + if (empty != _empty) continue; + } + if (_hasself != -1) + { + if (hasself != _hasself) continue; + } + if (_autoavail != -1) + { + if (autoavail != _autoavail) continue; + } + + if (cont != NULL) + { + if (c != cont) continue; + } + + if (lay != NULL) + { + if (l != lay) continue; + } + + if (g != INVALID_GUID) + { + if (h->wantGuid(g)) return h; + } + else if (group_id) + { + if (h->wantGroup(group_id)) return h; + } + endfor; + + return NULL; +} + +ifc_window *SkinEmbedder::create(GUID g, const wchar_t *groupid, const wchar_t *prefered_container, int container_flag, RECT *r, int transcient, int starthidden, int *isnew) +{ + // InCriticalSection in_cs(&skinembed_cs); + + foreach(in_deferred_callback) + SkinEmbedEntry *e = in_deferred_callback.getfor(); + if ((e->guid != INVALID_GUID && e->guid == g) || WCSCASEEQLSAFE(groupid, e->groupid)) + { +#ifdef _DEBUG + DebugStringW(L"trying to show a window that is being destroyed, hm, try again later\n"); +#endif + // too soon! try later dude + return NULL; + } + endfor; + + RECT destrect = {0}; + + if (isnew) *isnew = 0; + + WindowHolder *wh = NULL; + // todo: get from c++ callback + + if (SOM::checkAbortShowHideWindow(g, 1)) + return NULL; + + if (g != INVALID_GUID) + wh = SOM::getSuitableWindowHolderFromScript(g); + + if (!wh) wh = getSuitableWindowHolder(g, groupid, NULL, NULL, 1 /*visible*/, 0 /*static*/, 1 /*empty*/, -1 /*donttest*/, -1 /*donttest*/); + if (!wh) wh = getSuitableWindowHolder(g, groupid, NULL, NULL, 0 /*hidden*/, 0 /*static*/, 0 /*notempty*/, 1 /*hasself*/, -1 /*donttest*/); + if (!wh) wh = getSuitableWindowHolder(g, groupid, NULL, NULL, 0 /*hidden*/, 0 /*static*/, 1 /*empty*/, -1 /*donttest*/, 1 /*autoavail*/); + if (!wh) wh = getSuitableWindowHolder(g, groupid, NULL, NULL, 1 /*visible*/, 1 /*dynamic*/, 1 /*empty*/, -1 /*donttest*/, -1 /*donttest*/); + ifc_window *whrw = wh ? wh->getRootWndPtr() : NULL; + Container *cont = NULL; + Layout *lay = NULL; + ifc_window *wnd = NULL; + int newcont = 0; + + if (!wh) + { // no hidden static container, so lets create a dynamic one + if (isnew) *isnew = 1; + if (container_flag == 0 && (prefered_container == NULL || !*prefered_container)) + { + prefered_container = AutoPopup::getDefaultContainerParams(groupid, g, &container_flag); + } + if (container_flag == 0 && (prefered_container == NULL || !*prefered_container)) + { + prefered_container = WASABI_DEFAULT_STDCONTAINER; + } + cont = SkinParser::loadContainerForWindowHolder(groupid, g, 0, transcient, prefered_container, container_flag); + if (cont) + { + cont->setTranscient(transcient); + newcont = 1; + lay = cont->enumLayout(0); + /* if (prefered_layout) { // find its target layout + cont->setDefaultLayout(prefered_layout); + lay = cont->getLayout(prefered_layout); + if (!lay) { + if (!layout_flag) // see if we can fallback + lay = cont->enumLayout(0); + else { + destroyContainer(cont); // deferred + api->console_outputString(9, StringPrintf("could not find the requested layout (%s) to host the window", prefered_container)); + return NULL; + } + }*/ + } + else + { + DebugStringW(L"no container found to hold the window... not even a default one :/\n"); + } + wh = getSuitableWindowHolder(g, groupid, cont, lay, -1 /*donttest*/, -1 /*donttest*/, 0 /*notempty*/, 1 /*hasself*/, -1 /*donttest*/); + if (!wh) wh = getSuitableWindowHolder(g, groupid, cont, lay, -1 /*donttest*/, -1 /*donttest*/, 1 /*empty*/, -1 /*donttest*/, -1 /*donttest*/); + whrw = wh ? wh->getRootWndPtr() : NULL; + } + + if (wh) + { + GuiObject *o = static_cast<GuiObject *>(whrw->getInterface(guiObjectGuid)); + ASSERT(o != NULL); + if (o) + { + lay = o->guiobject_getParentLayout(); + if (lay) + cont = lay->getParentContainer(); + } + if ((g != INVALID_GUID && (g == wh->getCurGuid())) || (groupid && (wh->getCurGroupId() == groupid))) + wnd = wh->getCurRootWnd(); + else + { + if (wh->getCurRootWnd()) + wh->onRemoveWindow(); + wnd = wh->onInsertWindow(g, groupid); + } + } + + if (!wnd) + { + if (cont) + { + if (!WCSCASEEQLSAFE(cont->getId(), L"main")) + cont->close(); + } + return NULL; + } + + //int anim = 1; + //if (wh && !whrw->getAnimatedRects()) anim = 0; // FIXME!! + + if (lay && r) + { + lay->getWindowRect(&destrect); + } + + if (cont /*&& cont->isDynamic()*/) + { + const wchar_t *text = wnd->getRootWndName(); + cont->setTranscient(transcient); + if (text != NULL) + if (cont->isDynamic()) cont->setName(text); + if (cont->isDynamic() && !transcient) cont->resetLayouts(); + if (newcont) cont->onInit(1); + } + +#ifdef WASABI_COMPILE_CONFIG + // {280876CF-48C0-40bc-8E86-73CE6BB462E5} + const GUID options_guid = + { 0x280876cf, 0x48c0, 0x40bc, { 0x8e, 0x86, 0x73, 0xce, 0x6b, 0xb4, 0x62, 0xe5 } }; + CfgItem *cfgitem = WASABI_API_CONFIG->config_getCfgItemByGuid(options_guid); + int findopenrect = _int_getValue(cfgitem, L"Find open rect"); +#else + int findopenrect = WASABI_WNDMGR_FINDOPENRECT; +#endif + + if (wh && findopenrect) + { + if (lay) + { + RECT rl; + lay->getWindowRect(&rl); + RECT nr = windowTracker->findOpenRect(rl, lay); + destrect = nr; // rewrite destrect + int w = rl.right - rl.left; + int h = rl.bottom - rl.top; + lay->divRatio(&w, &h); + nr.right = nr.left + w; + nr.bottom = nr.top + h; + lay->resizeToRect(&nr); + } + } + + if (wh) + { + if (r) + /*if (anim)*/ WASABI_API_WNDMGR->drawAnimatedRects(r, &destrect); + /*else + { + RECT r; + r.left = destrect.left + (destrect.right - destrect.left) / 2 - 1; + r.top = destrect.top + (destrect.bottom - destrect.top) / 2 + 1; + r.right = r.left + 2; + r.bottom = r.top + 2; + if (anim) WASABI_API_WNDMGR->drawAnimatedRects(&r, &destrect); + }*/ + } + + if (!starthidden) + { + if (cont && cont->isVisible()) + { // we were already shown, duh + // cont->setVisible(0); + } + else + { + if (cont) cont->setVisible(1); + else if (lay) lay->setVisible(1); + } + } + + if (wnd && newcont && !transcient) + { + inserted.addItem(new SkinEmbedEntry(wnd->getDependencyPtr(), wnd, g, groupid, prefered_container, container_flag, cont, wh)); + viewer_addViewItem(wnd->getDependencyPtr()); + } + + if (!transcient && wnd) + allofthem.addItem(new SkinEmbedEntry(wnd->getDependencyPtr(), wnd, g, groupid, prefered_container, container_flag, cont, wh)); + + return wnd; +} + +void SkinEmbedder::destroy(ifc_window *w, RECT *r) +{ + int donecheck = 0; + SkinEmbedEntry *e = NULL; + for (int i = 0; i < allofthem.getNumItems();i++) + { + e = allofthem.enumItem(i); + if (e->wnd == w) + { + donecheck = 1; + if (SOM::checkAbortShowHideWindow(e->guid, 0)) + return ; + break; + } + } + if (WASABI_API_WND->rootwndIsValid(w)) + { + if (!donecheck) + { + ifc_window *ww = w->findWindowByInterface(windowHolderGuid); + if (ww) + { + WindowHolder *wh = static_cast<WindowHolder*>(ww->getInterface(windowHolderGuid)); + if (wh) + { + GUID g = wh->getCurGuid(); + if (g != INVALID_GUID) + { + donecheck = 1; + if (SOM::checkAbortShowHideWindow(g, 0)) + return ; + } + } + } + } + } + // checkAbort can render w invalid !!! check again + if (WASABI_API_WND->rootwndIsValid(w)) + { + ifc_window *wnd = w->getDesktopParent(); + GuiObject *go = static_cast<GuiObject *>(wnd->getInterface(guiObjectGuid)); + if (go) + { + Layout *l = go->guiobject_getParentLayout(); + if (l) + { + Container *c = l->getParentContainer(); + if (c) + { + if (!WCSCASEEQLSAFE(c->getId(), L"main")) + { + c->close(); // deferred if needed + } + else + { + softclose: + ifc_window *wnd = w->findWindowByInterface(windowHolderGuid); + if (wnd != NULL) + { + WindowHolder *wh = static_cast<WindowHolder *>(wnd->getInterface(windowHolderGuid)); + if (wh != NULL) + { + wh->onRemoveWindow(1); + } + } + } + } + else goto softclose; + } + } + } +} + +int SkinEmbedder::getNumItems(GUID g) +{ + int n = 0; + for (int i = 0;i < wndholders.getNumItems();i++) + if (wndholders.enumItem(i)->getRootWndPtr()->isVisible() && wndholders.enumItem(i)->getCurGuid() == g) n++; + return n; +} + +int SkinEmbedder::getNumItems(const wchar_t *groupid) +{ + int n = 0; + for (int i = 0;i < wndholders.getNumItems();i++) + { + WindowHolder *wh = wndholders.enumItem(i); + if (wh->getRootWndPtr()->isVisible() + && WCSCASEEQLSAFE(wh->getCurGroupId(), groupid)) + n++; + } + return n; +} + +ifc_window *SkinEmbedder::enumItem(GUID g, int n) +{ + ASSERT(n >= 0); + for (int i = 0;i < wndholders.getNumItems();i++) + { + WindowHolder *wh = wndholders.enumItem(i); + if (wh->getCurGuid() == g) + { + ifc_window *w = wh->getRootWndPtr(); + Container *c = NULL; + if (w) + { + w = w->getDesktopParent(); + if (w) + { + Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid)); + if (l) + { + c = l->getParentContainer(); + } + } + } + if (c && c->isVisible() || (!c && wndholders.enumItem(i)->getRootWndPtr()->isVisible())) + { + if (n == 0) + return wndholders.enumItem(i)->getCurRootWnd(); + n--; + } + } + } + return NULL; +} + +ifc_window *SkinEmbedder::enumItem(const wchar_t *groupid, int n) +{ + ASSERT(n >= 0); + for (int i = 0;i < wndholders.getNumItems();i++) + { + WindowHolder *wh = wndholders.enumItem(i); + const wchar_t *curgroupid = wndholders[i]->getCurGroupId(); + if (WCSCASEEQLSAFE(curgroupid, groupid)) + { + ifc_window *w = wh->getRootWndPtr(); + Container *c = NULL; + if (w) + { + w = w->getDesktopParent(); + if (w) + { + Layout *l = static_cast<Layout *>(w->getInterface(layoutGuid)); + if (l) + { + c = l->getParentContainer(); + } + } + } + if (c && c->isVisible() || (!c && wndholders.enumItem(i)->getRootWndPtr()->isVisible())) + { + if (n == 0) + return wndholders.enumItem(i)->getCurRootWnd(); + n--; + } + } + } + return NULL; +} + +void SkinEmbedder::registerWindowHolder(WindowHolder *wh) +{ + if (wndholders.haveItem(wh)) return ; + wndholders.addItem(wh); +} + +void SkinEmbedder::unregisterWindowHolder(WindowHolder *wh) +{ + if (!wndholders.haveItem(wh)) return ; + wndholders.removeItem(wh); +} + +int SkinEmbedder::viewer_onItemDeleted(api_dependent *item) +{ + foreach(in_deferred_callback) + if (in_deferred_callback.getfor()->dep == item) + in_deferred_callback.removeByPos(foreach_index); + endfor + foreach(inserted) + SkinEmbedEntry *e = inserted.getfor(); + if (e->dep == item) + { + inserted.removeItem(e); + allofthem.removeItem(e); + delete e; + break; + } + endfor; + foreach(allofthem) + SkinEmbedEntry *e = allofthem.getfor(); + if (e->dep == item) + { + allofthem.removeItem(e); + delete e; + break; + } + endfor; + return 1; +} + +void SkinEmbedder::cancelDestroyContainer(Container *c) +{ + if (!cancel_deferred_destroy.haveItem(c)) cancel_deferred_destroy.addItem(c); +} + +void SkinEmbedder::destroyContainer(Container *o) +{ + ASSERT(o); + //fg>disabled as of 11/4/2003, side effect of cancelling fullscreen video (ie, notifier while playing video fullscreen) + //delt with the problem in basewnd directly + //#ifdef WIN32 + //SetFocus(NULL); // FG> this avoids Win32 calling directly WM_KILLFOCUS into a child's wndproc (couldn't they just have posted the damn msg ?), who would then call some of his parent's virtual functions while it is being deleted + // perhaps it would be good to add a generic way to disable most child wnd messages while the parent is being deleted + //#endif + + cancel_deferred_destroy.removeItem(o); + + foreach(inserted) + SkinEmbedEntry *e = inserted.getfor(); + if (e->container == o) + { + if (!in_deferred_callback.haveItem(e)) + in_deferred_callback.addItem(e); + + break; + } + endfor + deferred_destroy.addItem(o); + timerclient_setTimer(CB_DESTROYCONTAINER, 20); + //o->setVisible(0); + //timerclient_postDeferredCallback(CB_DESTROYCONTAINER, (intptr_t)o); +} + +void SkinEmbedder::timerclient_timerCallback(int id) +{ + if (id == CB_DESTROYCONTAINER) + { + foreach(deferred_destroy) + Container *c = deferred_destroy.getfor(); + foreach(in_deferred_callback) + if (in_deferred_callback.getfor()->container == c) + { + in_deferred_callback.removeByPos(foreach_index); + } + endfor; + if (cancel_deferred_destroy.haveItem(c)) + { + continue; + } + if (SkinParser::isContainer(c)) // otherwise i'ts already gone while we were waiting for the callback, duh! + delete c; + endfor + cancel_deferred_destroy.removeAll(); + deferred_destroy.removeAll(); + timerclient_killTimer(CB_DESTROYCONTAINER); + return ; + } + TimerClientDI::timerclient_timerCallback(id); +} + +int SkinEmbedder::timerclient_onDeferredCallback(intptr_t p1, intptr_t p2) +{ + return TimerClientDI::timerclient_onDeferredCallback(p1, p2); +} + +#ifdef WASABI_COMPILE_CONFIG +void SkinEmbedder::saveState() +{ + int i = 0; + wchar_t t[1024] = {0}; + foreach(inserted) + SkinEmbedEntry *e = inserted.getfor(); + if (e->guid != INVALID_GUID) + { + nsGUID::toCharW(e->guid, t); + } + else + { + WCSCPYN(t, e->groupid, 1024); + } + WASABI_API_CONFIG->setStringPrivate(StringPrintfW(L"wndstatus/id/%d", i), t); + WASABI_API_CONFIG->setStringPrivate(StringPrintfW(L"wndstatus/layout/%d", i), !e->layout.isempty() ? e->layout.getValue() : L""); + WASABI_API_CONFIG->setIntPrivate(StringPrintfW(L"wndstatus/flag/%d", i), e->required); + i++; + endfor; + WASABI_API_CONFIG->setStringPrivate(StringPrintfW(L"wndstatus/id/%d", i), L""); + WASABI_API_CONFIG->setStringPrivate(StringPrintfW(L"wndstatus/layout/%d", i), L""); + WASABI_API_CONFIG->setIntPrivate(StringPrintfW(L"wndstatus/flag/%d", i), 0); +} + +void SkinEmbedder::restoreSavedState() +{ + int i = 0; + wchar_t t[1024] = {0}; + wchar_t l[256] = {0}; + while (1) + { + WASABI_API_CONFIG->getStringPrivate(StringPrintfW(L"wndstatus/id/%d", i), t, 1024, L""); + if (!*t) break; + WASABI_API_CONFIG->getStringPrivate(StringPrintfW(L"wndstatus/layout/%d", i), l, 256, L""); + int flag = WASABI_API_CONFIG->getIntPrivate(StringPrintfW(L"wndstatus/flag/%d", i), 0); + GUID g = nsGUID::fromCharW(t); + //ifc_window *created = NULL; + //int tried = 0; + if (g != INVALID_GUID) + { + ifc_window *w = enumItem(g, 0); + if (w == NULL) + { + //tried = 1; + /*created = */create(g, l, flag); + } + } + else + { + ifc_window *w = enumItem(t, 0); + if (w == NULL) + { + //tried = 1; + /*created = */create(t, l, flag); + } + } + /* if (tried && !created) { + for (int j=0;j<inserted.getNumItems();j++) { + SkinEmbedEntry *e = inserted.enumItem(j); + int yes = 0; + if (g != INVALID_GUID) { + if (e->guid == g && e->required == flag && STRCASEEQLSAFE(e->layout, l)) + yes = 1; + } else { + if (STRCASEEQLSAFE(e->groupid, t) && e->required == flag && STRCASEEQLSAFE(e->layout, l)) + yes = 1; + } + if (yes) { + inserted.removeByPos(j); + j--; + delete e; + } + } + }*/ + i++; + } +} +#endif + +void SkinEmbedder::attachToSkin(ifc_window *w, int side, int size) +{ + RECT r; + if (w == NULL) return ; + ifc_window *_w = w->getDesktopParent(); + if (_w == NULL) _w = w; + SkinParser::getSkinRect(&r, _w); + + switch (side) + { + case SKINWND_ATTACH_RIGHT: + _w->resize(r.right, r.top, size, r.bottom - r.top); + break; + case SKINWND_ATTACH_TOP: + _w->resize(r.left, r.top - size, r.right - r.left, size); + break; + case SKINWND_ATTACH_LEFT: + _w->resize(r.left - size, r.top, size, r.bottom - r.top); + break; + case SKINWND_ATTACH_BOTTOM: + _w->resize(r.left, r.bottom, r.right - r.left, size); + break; + } +} + +PtrList<SkinEmbedEntry> SkinEmbedder::in_deferred_callback; +PtrList<Container> SkinEmbedder::cancel_deferred_destroy; +PtrList<Container> SkinEmbedder::deferred_destroy; |