#include #include "skinembed.h" #include #include #include #include #include #include #include #include #include #include #include #include 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(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(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(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(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(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(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(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;jguid == 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 SkinEmbedder::in_deferred_callback; PtrList SkinEmbedder::cancel_deferred_destroy; PtrList SkinEmbedder::deferred_destroy;