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/wac/compon.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Wasabi/api/wac/compon.cpp')
-rw-r--r-- | Src/Wasabi/api/wac/compon.cpp | 480 |
1 files changed, 480 insertions, 0 deletions
diff --git a/Src/Wasabi/api/wac/compon.cpp b/Src/Wasabi/api/wac/compon.cpp new file mode 100644 index 00000000..12f66313 --- /dev/null +++ b/Src/Wasabi/api/wac/compon.cpp @@ -0,0 +1,480 @@ +#include <precomp.h> + +#include <bfc/wasabi_std.h> + +#include "compon.h" +//#include <api/wac/main.h> // CUT! + +#ifndef WASABINOMAINAPI +#include <api/metadb/metadb.h> +#include <api/wac/papi.h> +#endif +#include <api/script/objects/compoobj.h> +#include <api/wndmgr/container.h> +#include <api/skin/skinparse.h> +#include <api/wac/wac.h> +#include <api/script/objects/wacobj.h> +#include <api/wnd/wndtrack.h> +#include <api/script/objecttable.h> + +#include <api/config/items/cfgitemi.h> + +#include <bfc/loadlib.h> +//#include <bfc/util/profiler.h> +#include <api/locales/xlatstr.h> +#include <bfc/file/recursedir.h> + +#include <api/service/svc_enum.h> +#include <api/service/services.h> +#include <api/service/servicei.h> +#include <api/skin/skin.h> +#include <api/script/scriptmgr.h> +#include <bfc/parse/pathparse.h> + +#ifndef WASABINOMAINAPI +#include <api/api1.h> +#endif + +#include <api/application/wkc.h> +#include <api/wndmgr/skinembed.h> +#include <api/script/objects/compoobj.h> + +#include <api/wnd/usermsg.h> +#include <bfc/util/inifile.h> + +class CShutdownCallback { + public: + virtual void rl_onShutdown()=0; +}; + + +extern GUID baseGUID; + +static TList<GUID> loadlist, banlist; + +// compon.cpp : maintains the list of installed components, and installs +// each one + +// keep a list of component pointers as well as instances +class component_slot +{ +public: +#ifndef WASABINOMAINAPI + component_slot(Library *_dll, WaComponent *_wac, ComponentAPI *_api, GUID g, const wchar_t *orig_path) + : dll(_dll), wac(_wac), path(orig_path), guid(g), componentapi(_api) { +#else + component_slot(Library *_dll, WaComponent *_wac, GUID g, const wchar_t *orig_path) + : dll(_dll), wac(_wac), path(orig_path), guid(g) { +#endif + int fnlen = wcslen(Wasabi::Std::filename(orig_path)); + path.trunc(-fnlen); + postonregsvcs = 0; + postoncreate = 0; + loadearly = 0; // will be filled in later + } + ~component_slot() { +#ifndef WASABINOMAINAPI + if (dll != NULL) PAPI::destroyAPI(componentapi); +#endif + delete dll; + } + void registerServices() { +#ifndef WASABINOMAINAPI + if (!postonregsvcs) wac->registerServices(componentapi); +#else + if (!postonregsvcs) wac->registerServices(WASABI_API_SVC); +#endif + postonregsvcs = 1; + } + void onCreate() { + if (!postoncreate) wac->onCreate(); + postoncreate = 1; + } + + Library *dll; + WaComponent *wac; // we don't delete this + StringW path; + GUID guid; // prevent spoofing +#ifndef WASABINOMAINAPI + ComponentAPI *componentapi; +#endif + int postoncreate; + int postonregsvcs; + int loadearly; +}; + +static PtrList<component_slot> components; + +/*static PtrList<cd_entry> cd_list; +static PtrList<ComponentObject> co_list;*/ + +// the minimum SDK version # we accept +const int WA_COMPONENT_VER_MIN = WA_COMPONENT_VERSION; + + static int postComponentCommand(GUID guid, const wchar_t *command, int p1, int p2, void *ptr, int ptrlen, int waitforanswer); + +class ComponPostEntry { +public: + ComponPostEntry(GUID pguid, const wchar_t *pcommand, int pp1, int pp2, void *pptr, int pptrlen, int pwait) : + guid(pguid), command(pcommand), p1(pp1), p2(pp2), ptr(pptr), ptrlen(pptrlen), waitforanswer(pwait), + posted(0), result(0) { } + GUID guid; + StringW command; + int p1, p2; + void *ptr; + int ptrlen; + int waitforanswer; + int posted; + int result; +}; + +static PtrList<StringW> preloads; + +void ComponentManager::addStaticComponent(WaComponent *component) { + GUID guid = component->getGUID(); + if (!checkGUID(guid)) return; // guid check (banlist etc.) + +#ifndef WASABINOMAINAPI + // reuse main api * + components.addItem(new component_slot(NULL, component, api, guid, NULL)); +#else + components.addItem(new component_slot(NULL, component, guid, NULL)); +#endif +} + +void ComponentManager::addPreloadComponent(const wchar_t *filename) +{ + foreach(preloads) + if (PATHEQL(filename, preloads.getfor()->getValue())) return;// no dups + endfor + preloads.addItem(new StringW(filename)); +} + +void ComponentManager::loadPreloads() { + foreach(preloads) + load(preloads.getfor()->getValue()); + endfor + preloads.deleteAll(); +} + +void ComponentManager::load(const wchar_t *filename) { + // ensure no duplicate filenames + foreach(components) + if (PATHEQL(filename, components.getfor()->dll->getName())) return; + endfor + + #ifdef WA3COMPATIBILITY + // let kernel controller test the file + WasabiKernelController *wkc = Main::getKernelController(); + if (wkc && !wkc->testComponent(filename)) return; + #endif + + // check if they have an ini (to get guid faster) + StringW inifile = filename; + const wchar_t *ext = Wasabi::Std::extension(inifile); + int len = wcslen(ext); + inifile.trunc(-len); + inifile.cat(L"ini"); + IniFile ini(inifile); + GUID ini_guid = ini.getGuid(L"component", L"guid"); + if (!checkGUID(ini_guid, TRUE)) return; + +// PR_ENTER2("load component", filename); + + // attach the DLL + Library *dll = new Library(filename); + if (!dll->load()) { + delete dll; + return; + } + + // check the version of SDK it was compiled with + WACGETVERSION wac_get_version = (WACGETVERSION)dll->getProcAddress("WAC_getVersion"); + if (wac_get_version == NULL) { + delete dll; + return; + } + + int version = (*wac_get_version)(); + if (version < WA_COMPONENT_VER_MIN || // defined above + version > WA_COMPONENT_VERSION) { // from wac.h + delete dll; + return; + } + + // init the dll itself + WACINIT wacinit = (WACINIT)dll->getProcAddress("WAC_init"); + if (wacinit != NULL) (*wacinit)(dll->getHandle()); + + WACENUMCOMPONENT wec = (WACENUMCOMPONENT)dll->getProcAddress("WAC_enumComponent"); + if (wec == NULL) { + delete dll; + return; + } + + // fetch the pointer + WaComponent *wac = (*wec)(0); + + GUID guid = wac->getGUID(); + + if (ini_guid != INVALID_GUID && guid != ini_guid) { + delete dll; + DebugString("guids didn't match! %s", filename); + return; + } + + // check if we want to load this GUID + if (!checkGUID(guid)) { + delete dll; + return; + } + +#ifndef WASABINOMAINAPI + // allocate an api pointer bound to their GUID + ComponentAPI *newapi = PAPI::createAPI(wac, guid); + if (newapi == NULL) { + delete dll; + return; + } +#endif + + PathParserW pp(filename); + StringW path; + for (int i=0;i<pp.getNumStrings()-1;i++) + { + path.AppendFolder(pp.enumString(i)); + } + + wac->setComponentPath(path); + + // keep track of dll handles for shutdown + components.addItem(new component_slot(dll, wac, +#ifndef WASABINOMAINAPI + newapi, +#endif + guid, filename)); + +// PR_LEAVE(); +} + +const wchar_t *ComponentManager::getComponentPath(GUID g) { + foreach(components) + if (g == components.getfor()->guid) { + return components.getfor()->path; + } + endfor + return NULL; +} + +void ComponentManager::startupDBs() { +/* for (int i=0;i<components.getNumItems();i++) + MetaDB::addComponentDB(components.enumItem(i)->wac);*/ +} + +void ComponentManager::shutdownDBs() { +#ifndef WASABINOMAINAPI + for (int i = 0; i < components.getNumItems(); i++) { + //MetaDB::getBaseDB()->removeComponentDB(components[i]->wac); + (static_cast<ComponentAPI1 *>(components[i]->componentapi))->shutdownDB(); + } +#else +//MULTIAPI-FIXME: solve the shutdownDB puzzle +#endif +} + +void ComponentManager::unloadAll() { + // cable out! let 'er go! +// deleteAllCD(); // deletes compwnds + foreach(components) + components.getfor()->wac->deregisterServices(); + endfor + foreach(components) + components.getfor()->wac->onDestroy(); + endfor + components.deleteAll(); // free the DLLs, and kill their API *'s +} + +int ComponentManager::checkGUID(GUID &g, int invalid_ok) { + // no invalid guid + if (!invalid_ok && g == INVALID_GUID) return FALSE; + + // check against banlist + if (banlist.haveItem(g)) return FALSE; + + // check against load-only list + if (loadlist.getNumItems() && !loadlist.haveItem(g)) return FALSE; + + // ensure no duplicate GUIDs + foreach(components) + if (g == components.getfor()->guid) { +//CUT StringPrintf s("%s and %s", components.getfor()->dll->getName(), filename); +//CUT Std::messageBox(s, "Duplicate component guid", MB_OK); + return FALSE; + } + endfor + + // ok + return TRUE; +} + +WaComponent *ComponentManager::enumComponent(int component) { + if (component < 0 || component >= components.getNumItems()) return NULL; + return components[component]->wac; +} + +void ComponentManager::loadAll(const wchar_t *path) { + +#if 0//CUT + static const char *loadorder[] = { + "wasabi.system/pngload.wac", + "wasabi.player/core.wac", + "metrics.wac", // so metrics dialog appears before the splash screen + "winamp/winamp.wac", // so splash screen displays right after startup + "winamp/pledit.wac", + "winamp/library.wac", + "preferences.wac", // so prefs has the system groups at the top + "skinswitch.wac", // so skinswitch is the first non internal prefs screen, ignored if not present. fucko: need to modify prefs system so we don't need to load in any particular order + NULL + }; + + for (int i = 0; loadorder[i] != NULL; i++) { + StringPrintf fn("%s%s%s", WACDIR, DIRCHARSTR, loadorder[i]); + ComponentManager::load(fn); + } +#endif + RecurseDir dir(path, L"*.*");// have to do *.* to get subdirs + while (dir.next()) { + StringPathCombine fn(dir.getPath(), dir.getFilename()); + const wchar_t *ext = Wasabi::Std::extension(fn); + if (!WCSICMP(ext, L"wac")) + ComponentManager::load(fn); + } +} + +void ComponentManager::postLoad(int f) { // two-level startup procedure + // note we're calling the slot, not the component directly + + // allow punk-ass bitches to load early if need be + foreach(components) + if ((components.getfor()->loadearly = !!components.getfor()->wac->onNotify(WAC_NOTIFY_LOADEARLY))) { + components.getfor()->registerServices(); + } + endfor + + foreach(components) + if (!components.getfor()->loadearly) + components.getfor()->registerServices(); + endfor + foreach(components) + components.getfor()->onCreate(); + endfor + if (f) ObjectTable::loadExternalClasses(); +} + +void ComponentManager::broadcastNotify(int cmd, int param1, int param2) { + foreach(components) + if ((components.getfor()->loadearly = !!components.getfor()->wac->onNotify(WAC_NOTIFY_LOADEARLY, cmd, param1, param2))) + components.getfor()->wac->onNotify(cmd, param1, param2); + endfor + foreach(components) + if (!components.getfor()->loadearly) + components.getfor()->wac->onNotify(cmd, param1, param2); + endfor +} + +void ComponentManager::sendNotify(GUID guid, int cmd, int param1, int param2) { + WaComponent *wac = getComponentFromGuid(guid); + if (wac) + wac->onNotify(cmd, param1, param2); +} + +int ComponentManager::sendCommand(GUID guid, const wchar_t *command, int p1, int p2, void *ptr, int ptrlen) { + if (command == NULL) return 0; + WaComponent *wac = getComponentFromGuid(guid); + if (wac) return wac->onCommand(command, p1, p2, ptr, ptrlen); + return 0; +} + +int ComponentManager::postCommand(GUID guid, const wchar_t *command, int p1, int p2, void *ptr, int ptrlen, int waitforanswer) { +#ifdef WA3COMPATIBILITY // todo: make thread id part of application api + if(Std::getCurrentThreadId()==Main::getThreadId() && waitforanswer) { + // if it is already the main thread calling, just pass the command to sendCommand + return sendCommand(guid,command,p1,p2,ptr,ptrlen); + } +#endif + ComponPostEntry *cpe=new ComponPostEntry(guid,command,p1,p2,ptr,ptrlen,waitforanswer); + componPostEntries.addItem(cpe); +#ifdef WIN32 +#ifdef WA3COMPATIBILITY // todo: make this a call to application api + PostMessage(Main::gethWnd(),UMSG_COMPON_POSTMESSAGE,0,0); // ask the main thread to call mainthreadpostCommands(); +#endif +#else + PostMessage(None,UMSG_COMPON_POSTMESSAGE,0,0); // ask the main thread to call mainthreadpostCommands(); +#endif + if(waitforanswer) { + while(!cpe->posted) Sleep(1); + int res=cpe->result; + componPostEntries.removeItem(cpe); + delete(cpe); + return res; + } + return 0; // cpe will get deleted by mainthreadpostCommands(); +} + + +void ComponentManager::broadcastCommand(const wchar_t *command, int p1, int p2, void *ptr, int ptrlen) { + if (command == NULL) return; + for (int i = 0; i < components.getNumItems(); i++) { + components[i]->wac->onCommand(command, p1, p2, ptr, ptrlen); + } +} + +int ComponentManager::getNumComponents() { + return components.getNumItems(); +} + +GUID ComponentManager::getComponentGUID(int c) { + if (c >= components.getNumItems()) return INVALID_GUID; + return components[c]->guid; +} + +const wchar_t *ComponentManager::getComponentName(GUID g) +{ + WaComponent *wac = getComponentFromGuid(g); + if (wac) + return wac->getName(); + return NULL; +} + +CfgItem *ComponentManager::getCfgInterface(GUID g) { + WaComponent *wac = getComponentFromGuid(g); + if (wac == NULL) return NULL; + return wac->getCfgInterface(0); +} + +WaComponent *ComponentManager::getComponentFromGuid(GUID g) { + if (g == INVALID_GUID) return NULL; + for (int i=0;i<components.getNumItems();i++) { + if (g == components[i]->guid) + return components[i]->wac; + } + return NULL; +} + +void ComponentManager::mainThread_handlePostCommands() { + // critical section + for(int i=0;i<componPostEntries.getNumItems();i++) { + ComponPostEntry *cpe=componPostEntries[i]; + if(!cpe->posted) { + sendCommand(cpe->guid,cpe->command.getValue(),cpe->p1,cpe->p2,cpe->ptr,cpe->ptrlen); + if(cpe->waitforanswer) cpe->posted=1; + else { + delete cpe; + componPostEntries.removeByPos(i); + i--; + } + } + } +} + +PtrList<ComponPostEntry> ComponentManager::componPostEntries; |