Pluginstags/v0.5.0
@@ -7,15 +7,15 @@ | |||||
namespace rack { | namespace rack { | ||||
/** Searches for a global read-only resource and returns its path, or "" if not found | |||||
/** Returns the path of a global resource. Read-only | |||||
*/ | */ | ||||
std::string assetGlobal(std::string filename); | std::string assetGlobal(std::string filename); | ||||
/** Searches for a local resource | |||||
/** Returns the path of a local resource. Read/write | |||||
*/ | */ | ||||
std::string assetLocal(std::string filename); | std::string assetLocal(std::string filename); | ||||
/** Searches for a manufacturer resource, given a Manufacturer object | |||||
/** Returns the path of a resource in the plugin's folder. Read-only | |||||
*/ | */ | ||||
std::string assetManufacturer(Manufacturer *manufacturer, std::string filename); | |||||
std::string assetPlugin(Plugin *plugin, std::string filename); | |||||
} // namespace rack | } // namespace rack |
@@ -10,41 +10,42 @@ struct ModuleWidget; | |||||
struct Model; | struct Model; | ||||
// Subclass this and return a pointer to a new one when init() is called | // Subclass this and return a pointer to a new one when init() is called | ||||
struct Manufacturer { | |||||
/** A list of the models available by this manufacturer, add with addModel() */ | |||||
struct Plugin { | |||||
/** A list of the models available by this plugin, add with addModel() */ | |||||
std::list<Model*> models; | std::list<Model*> models; | ||||
/** The file path of the plugins directory */ | |||||
/** The file path of the plugin's directory */ | |||||
std::string path; | std::string path; | ||||
/** OS-dependent library handle */ | /** OS-dependent library handle */ | ||||
void *handle = NULL; | void *handle = NULL; | ||||
// You may set everything below this point in your plugin | |||||
/** A unique identifier for the manufacturer, e.g. "foo" */ | |||||
/** Used when syncing plugins with the API */ | |||||
std::string slug; | std::string slug; | ||||
/** Human readable name for the manufacturer, e.g. "Foo Modular" */ | |||||
std::string name; | |||||
/** Optional metadata for the Add Module context menu */ | |||||
std::string homepageUrl; | |||||
std::string manualUrl; | |||||
/** The version of your plugin | |||||
Plugins should follow the versioning scheme described at https://github.com/VCVRack/Rack/issues/266 | |||||
Do not include the "v" in "v1.0" for example. | |||||
*/ | |||||
std::string version; | std::string version; | ||||
virtual ~Manufacturer(); | |||||
virtual ~Plugin(); | |||||
void addModel(Model *model); | void addModel(Model *model); | ||||
}; | }; | ||||
struct Model { | struct Model { | ||||
Manufacturer *manufacturer = NULL; | |||||
/** A unique identifier for the model, e.g. "VCO" */ | |||||
Plugin *plugin = NULL; | |||||
/** An identifier for the model, e.g. "VCO". Used for saving patches. The slug, manufacturerSlug pair must be unique. */ | |||||
std::string slug; | std::string slug; | ||||
/** Human readable name for your model, e.g. "Voltage Controlled Oscillator" */ | /** Human readable name for your model, e.g. "Voltage Controlled Oscillator" */ | ||||
std::string name; | std::string name; | ||||
/** An identifier for the manufacturer, e.g. "foo". Used for saving patches. */ | |||||
std::string manufacturerSlug; | |||||
/** Human readable name for the manufacturer, e.g. "Foo Modular" */ | |||||
std::string manufacturerName; | |||||
virtual ~Model() {} | virtual ~Model() {} | ||||
virtual ModuleWidget *createModuleWidget() { return NULL; } | virtual ModuleWidget *createModuleWidget() { return NULL; } | ||||
}; | }; | ||||
extern std::list<Manufacturer*> gManufacturers; | |||||
extern std::list<Plugin*> gPlugins; | |||||
extern std::string gToken; | extern std::string gToken; | ||||
void pluginInit(); | void pluginInit(); | ||||
@@ -66,8 +67,8 @@ std::string pluginGetLoginStatus(); | |||||
// Implemented by plugin | // Implemented by plugin | ||||
//////////////////// | //////////////////// | ||||
/** Called once to initialize and return the Manufacturer instance. | |||||
/** Called once to initialize and return the Plugin instance. | |||||
You must implement this in your plugin | You must implement this in your plugin | ||||
*/ | */ | ||||
extern "C" | extern "C" | ||||
void init(rack::Manufacturer *manufacturer); | |||||
void init(rack::Plugin *plugin); |
@@ -18,7 +18,7 @@ namespace rack { | |||||
//////////////////// | //////////////////// | ||||
template <class TModuleWidget> | template <class TModuleWidget> | ||||
Model *createModel(std::string slug, std::string name) { | |||||
Model *createModel(std::string manufacturerSlug, std::string manufacturerName, std::string slug, std::string name) { | |||||
struct TModel : Model { | struct TModel : Model { | ||||
ModuleWidget *createModuleWidget() override { | ModuleWidget *createModuleWidget() override { | ||||
ModuleWidget *moduleWidget = new TModuleWidget(); | ModuleWidget *moduleWidget = new TModuleWidget(); | ||||
@@ -29,6 +29,8 @@ Model *createModel(std::string slug, std::string name) { | |||||
Model *model = new TModel(); | Model *model = new TModel(); | ||||
model->slug = slug; | model->slug = slug; | ||||
model->name = name; | model->name = name; | ||||
model->manufacturerSlug = manufacturerSlug; | |||||
model->manufacturerName = manufacturerName; | |||||
return model; | return model; | ||||
} | } | ||||
@@ -45,8 +45,8 @@ void ModuleWidget::addParam(ParamWidget *param) { | |||||
json_t *ModuleWidget::toJson() { | json_t *ModuleWidget::toJson() { | ||||
json_t *rootJ = json_object(); | json_t *rootJ = json_object(); | ||||
// plugin | |||||
json_object_set_new(rootJ, "plugin", json_string(model->manufacturer->slug.c_str())); | |||||
// manufacturer | |||||
json_object_set_new(rootJ, "manufacturer", json_string(model->manufacturerSlug.c_str())); | |||||
// model | // model | ||||
json_object_set_new(rootJ, "model", json_string(model->slug.c_str())); | json_object_set_new(rootJ, "model", json_string(model->slug.c_str())); | ||||
// pos | // pos | ||||
@@ -245,7 +245,7 @@ Menu *ModuleWidget::createContextMenu() { | |||||
Menu *menu = gScene->createMenu(); | Menu *menu = gScene->createMenu(); | ||||
MenuLabel *menuLabel = new MenuLabel(); | MenuLabel *menuLabel = new MenuLabel(); | ||||
menuLabel->text = model->manufacturer->name + ": " + model->name; | |||||
menuLabel->text = model->manufacturerName + " " + model->name; | |||||
menu->pushChild(menuLabel); | menu->pushChild(menuLabel); | ||||
ResetMenuItem *resetItem = new ResetMenuItem(); | ResetMenuItem *resetItem = new ResetMenuItem(); | ||||
@@ -1,12 +1,13 @@ | |||||
#include <map> | |||||
#include <algorithm> | |||||
#include <thread> | |||||
#include "app.hpp" | #include "app.hpp" | ||||
#include "engine.hpp" | #include "engine.hpp" | ||||
#include "plugin.hpp" | #include "plugin.hpp" | ||||
#include "gui.hpp" | #include "gui.hpp" | ||||
#include "settings.hpp" | #include "settings.hpp" | ||||
#include "asset.hpp" | #include "asset.hpp" | ||||
#include <map> | |||||
#include <algorithm> | |||||
#include <thread> | |||||
#include <set> | |||||
#include "../ext/osdialog/osdialog.h" | #include "../ext/osdialog/osdialog.h" | ||||
@@ -200,36 +201,29 @@ void RackWidget::fromJson(json_t *rootJ) { | |||||
size_t moduleId; | size_t moduleId; | ||||
json_t *moduleJ; | json_t *moduleJ; | ||||
json_array_foreach(modulesJ, moduleId, moduleJ) { | json_array_foreach(modulesJ, moduleId, moduleJ) { | ||||
json_t *pluginSlugJ = json_object_get(moduleJ, "plugin"); | |||||
if (!pluginSlugJ) continue; | |||||
json_t *manufacturerSlugJ = json_object_get(moduleJ, "manufacturer"); | |||||
if (!manufacturerSlugJ) { | |||||
// Backward compatibility with Rack v0.4 and lower | |||||
manufacturerSlugJ = json_object_get(moduleJ, "plugin"); | |||||
if (!manufacturerSlugJ) continue; | |||||
} | |||||
json_t *modelSlugJ = json_object_get(moduleJ, "model"); | json_t *modelSlugJ = json_object_get(moduleJ, "model"); | ||||
if (!modelSlugJ) continue; | if (!modelSlugJ) continue; | ||||
const char *pluginSlug = json_string_value(pluginSlugJ); | |||||
const char *modelSlug = json_string_value(modelSlugJ); | |||||
// Search for plugin | |||||
Manufacturer *manufacturer = NULL; | |||||
for (Manufacturer *m : gManufacturers) { | |||||
if (m->slug == pluginSlug) { | |||||
manufacturer = m; | |||||
break; | |||||
} | |||||
} | |||||
if (!manufacturer) { | |||||
message += stringf("Could not find plugin \"%s\" for module \"%s\".\n", pluginSlug, modelSlug); | |||||
continue; | |||||
} | |||||
std::string manufacturerSlug = json_string_value(manufacturerSlugJ); | |||||
std::string modelSlug = json_string_value(modelSlugJ); | |||||
// Get for model | |||||
// Search for model | |||||
Model *model = NULL; | Model *model = NULL; | ||||
for (Model *m : manufacturer->models) { | |||||
if (m->slug == modelSlug) { | |||||
model = m; | |||||
break; | |||||
for (Plugin *plugin : gPlugins) { | |||||
for (Model *m : plugin->models) { | |||||
if (m->manufacturerSlug == manufacturerSlug && m->slug == modelSlug) { | |||||
model = m; | |||||
} | |||||
} | } | ||||
} | } | ||||
if (!model) { | if (!model) { | ||||
message += stringf("Could not find module \"%s\" in plugin \"%s\".\n", modelSlug, pluginSlug); | |||||
message += stringf("Could not find \"%s %s\" module\n", manufacturerSlug.c_str(), modelSlug.c_str()); | |||||
continue; | continue; | ||||
} | } | ||||
@@ -389,12 +383,22 @@ struct UrlItem : MenuItem { | |||||
}; | }; | ||||
struct AddManufacturerMenuItem : MenuItem { | struct AddManufacturerMenuItem : MenuItem { | ||||
Manufacturer *manufacturer; | |||||
std::string manufacturerName; | |||||
Vec modulePos; | Vec modulePos; | ||||
Menu *createChildMenu() override { | Menu *createChildMenu() override { | ||||
// Collect models which have this manufacturer name | |||||
std::set<Model*> models; | |||||
for (Plugin *plugin : gPlugins) { | |||||
for (Model *model : plugin->models) { | |||||
if (model->manufacturerName == manufacturerName) { | |||||
models.insert(model); | |||||
} | |||||
} | |||||
} | |||||
// Model items | // Model items | ||||
Menu *menu = new Menu(); | Menu *menu = new Menu(); | ||||
for (Model *model : manufacturer->models) { | |||||
for (Model *model : models) { | |||||
AddModuleMenuItem *item = new AddModuleMenuItem(); | AddModuleMenuItem *item = new AddModuleMenuItem(); | ||||
item->text = model->name; | item->text = model->name; | ||||
item->model = model; | item->model = model; | ||||
@@ -403,42 +407,44 @@ struct AddManufacturerMenuItem : MenuItem { | |||||
} | } | ||||
// Metadata items | // Metadata items | ||||
/* | |||||
{ | { | ||||
MenuLabel *label = new MenuLabel(); | MenuLabel *label = new MenuLabel(); | ||||
menu->pushChild(label); | menu->pushChild(label); | ||||
} | } | ||||
{ | { | ||||
MenuLabel *label = new MenuLabel(); | MenuLabel *label = new MenuLabel(); | ||||
label->text = manufacturer->name; | |||||
label->text = plugin->name; | |||||
menu->pushChild(label); | menu->pushChild(label); | ||||
} | } | ||||
if (!manufacturer->homepageUrl.empty()) { | |||||
if (!plugin->homepageUrl.empty()) { | |||||
UrlItem *item = new UrlItem(); | UrlItem *item = new UrlItem(); | ||||
item->text = "Homepage"; | item->text = "Homepage"; | ||||
item->url = manufacturer->homepageUrl; | |||||
item->url = plugin->homepageUrl; | |||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
if (!manufacturer->manualUrl.empty()) { | |||||
if (!plugin->manualUrl.empty()) { | |||||
UrlItem *item = new UrlItem(); | UrlItem *item = new UrlItem(); | ||||
item->text = "Manual"; | item->text = "Manual"; | ||||
item->url = manufacturer->manualUrl; | |||||
item->url = plugin->manualUrl; | |||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
if (!manufacturer->path.empty()) { | |||||
if (!plugin->path.empty()) { | |||||
UrlItem *item = new UrlItem(); | UrlItem *item = new UrlItem(); | ||||
item->text = "Browse directory"; | item->text = "Browse directory"; | ||||
item->url = manufacturer->path; | |||||
item->url = plugin->path; | |||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
if (!manufacturer->version.empty()) { | |||||
if (!plugin->version.empty()) { | |||||
MenuLabel *item = new MenuLabel(); | MenuLabel *item = new MenuLabel(); | ||||
item->text = "Version: v" + manufacturer->version; | |||||
item->text = "Version: v" + plugin->version; | |||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
*/ | |||||
return menu; | return menu; | ||||
} | } | ||||
@@ -452,10 +458,18 @@ void RackWidget::onMouseDownOpaque(int button) { | |||||
MenuLabel *menuLabel = new MenuLabel(); | MenuLabel *menuLabel = new MenuLabel(); | ||||
menuLabel->text = "Add module"; | menuLabel->text = "Add module"; | ||||
menu->pushChild(menuLabel); | menu->pushChild(menuLabel); | ||||
for (Manufacturer *manufacturer : gManufacturers) { | |||||
// Collect manufacturer names | |||||
std::set<std::string> manufacturerNames; | |||||
for (Plugin *plugin : gPlugins) { | |||||
for (Model *model : plugin->models) { | |||||
manufacturerNames.insert(model->manufacturerName); | |||||
} | |||||
} | |||||
// Add menu item for each manufacturer name | |||||
for (std::string manufacturerName : manufacturerNames) { | |||||
AddManufacturerMenuItem *item = new AddManufacturerMenuItem(); | AddManufacturerMenuItem *item = new AddManufacturerMenuItem(); | ||||
item->text = manufacturer->name; | |||||
item->manufacturer = manufacturer; | |||||
item->text = manufacturerName; | |||||
item->manufacturerName = manufacturerName; | |||||
item->modulePos = modulePos; | item->modulePos = modulePos; | ||||
menu->pushChild(item); | menu->pushChild(item); | ||||
} | } | ||||
@@ -88,10 +88,10 @@ std::string assetLocal(std::string filename) { | |||||
return path; | return path; | ||||
} | } | ||||
std::string assetManufacturer(Manufacturer *manufacturer, std::string filename) { | |||||
assert(manufacturer); | |||||
std::string assetPlugin(Plugin *plugin, std::string filename) { | |||||
assert(plugin); | |||||
std::string path; | std::string path; | ||||
path = manufacturer->path + "/" + filename; | |||||
path = plugin->path + "/" + filename; | |||||
return path; | return path; | ||||
} | } | ||||
@@ -0,0 +1,44 @@ | |||||
#include "core.hpp" | |||||
using namespace rack; | |||||
NotesWidget::NotesWidget() { | |||||
box.size = Vec(RACK_GRID_WIDTH * 18, RACK_GRID_HEIGHT); | |||||
{ | |||||
Panel *panel = new LightPanel(); | |||||
panel->box.size = box.size; | |||||
addChild(panel); | |||||
} | |||||
addChild(createScrew<ScrewSilver>(Vec(15, 0))); | |||||
addChild(createScrew<ScrewSilver>(Vec(15, 365))); | |||||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 0))); | |||||
addChild(createScrew<ScrewSilver>(Vec(box.size.x - 30, 365))); | |||||
textField = new TextField(); | |||||
textField->box.pos = Vec(15, 15); | |||||
textField->box.size = box.size.minus(Vec(30, 30)); | |||||
textField->multiline = true; | |||||
addChild(textField); | |||||
} | |||||
json_t *NotesWidget::toJson() { | |||||
json_t *rootJ = ModuleWidget::toJson(); | |||||
// text | |||||
json_object_set_new(rootJ, "text", json_string(textField->text.c_str())); | |||||
return rootJ; | |||||
} | |||||
void NotesWidget::fromJson(json_t *rootJ) { | |||||
ModuleWidget::fromJson(rootJ); | |||||
// text | |||||
json_t *textJ = json_object_get(rootJ, "text"); | |||||
if (textJ) | |||||
textField->text = json_string_value(textJ); | |||||
} |
@@ -2,16 +2,14 @@ | |||||
#include "MidiIO.hpp" | #include "MidiIO.hpp" | ||||
void init(rack::Manufacturer *m) { | |||||
m->slug = "Core"; | |||||
m->name = "Core"; | |||||
m->homepageUrl = "https://vcvrack.com/"; | |||||
m->addModel(createModel<AudioInterfaceWidget>("AudioInterface", "Audio Interface")); | |||||
m->addModel(createModel<MidiToCVWidget>("MIDIToCVInterface", "MIDI-to-CV Interface")); | |||||
m->addModel(createModel<MIDICCToCVWidget>("MIDICCToCVInterface", "MIDI CC-to-CV Interface")); | |||||
m->addModel(createModel<MIDIClockToCVWidget>("MIDIClockToCVInterface", "MIDI Clock-to-CV Interface")); | |||||
m->addModel(createModel<MIDITriggerToCVWidget>("MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface")); | |||||
// m->addModel(createModel<BridgeWidget>("Bridge", "Bridge")); | |||||
m->addModel(createModel<BlankWidget>("Blank", "Blank")); | |||||
m->addModel(createModel<NotesWidget>("Notes", "Notes")); | |||||
void init(rack::Plugin *p) { | |||||
p->slug = "Core"; | |||||
p->addModel(createModel<AudioInterfaceWidget>("Core", "Core", "AudioInterface", "Audio Interface")); | |||||
p->addModel(createModel<MidiToCVWidget>("Core", "Core", "MIDIToCVInterface", "MIDI-to-CV Interface")); | |||||
p->addModel(createModel<MIDICCToCVWidget>("Core", "Core", "MIDICCToCVInterface", "MIDI CC-to-CV Interface")); | |||||
p->addModel(createModel<MIDIClockToCVWidget>("Core", "Core", "MIDIClockToCVInterface", "MIDI Clock-to-CV Interface")); | |||||
p->addModel(createModel<MIDITriggerToCVWidget>("Core", "Core", "MIDITriggerToCVInterface", "MIDI Trigger-to-CV Interface")); | |||||
// p->addModel(createModel<BridgeWidget>("Core", "Core", "Bridge", "Bridge")); | |||||
p->addModel(createModel<BlankWidget>("Core", "Core", "Blank", "Blank")); | |||||
p->addModel(createModel<NotesWidget>("Core", "Core", "Notes", "Notes")); | |||||
} | } |
@@ -28,7 +28,7 @@ | |||||
namespace rack { | namespace rack { | ||||
std::list<Manufacturer*> gManufacturers; | |||||
std::list<Plugin*> gPlugins; | |||||
std::string gToken; | std::string gToken; | ||||
static bool isDownloading = false; | static bool isDownloading = false; | ||||
@@ -38,15 +38,15 @@ static std::string loginStatus; | |||||
Manufacturer::~Manufacturer() { | |||||
Plugin::~Plugin() { | |||||
for (Model *model : models) { | for (Model *model : models) { | ||||
delete model; | delete model; | ||||
} | } | ||||
} | } | ||||
void Manufacturer::addModel(Model *model) { | |||||
assert(!model->manufacturer); | |||||
model->manufacturer = this; | |||||
void Plugin::addModel(Model *model) { | |||||
assert(!model->plugin); | |||||
model->plugin = this; | |||||
models.push_back(model); | models.push_back(model); | ||||
} | } | ||||
@@ -78,7 +78,7 @@ static int loadPlugin(std::string path) { | |||||
#endif | #endif | ||||
// Call plugin's init() function | // Call plugin's init() function | ||||
typedef void (*InitCallback)(Manufacturer *); | |||||
typedef void (*InitCallback)(Plugin *); | |||||
InitCallback initCallback; | InitCallback initCallback; | ||||
#if ARCH_WIN | #if ARCH_WIN | ||||
initCallback = (InitCallback) GetProcAddress(handle, "init"); | initCallback = (InitCallback) GetProcAddress(handle, "init"); | ||||
@@ -90,19 +90,14 @@ static int loadPlugin(std::string path) { | |||||
return -2; | return -2; | ||||
} | } | ||||
// Construct and initialize Manufacturer instance | |||||
Manufacturer *manufacturer = new Manufacturer(); | |||||
manufacturer->path = path; | |||||
manufacturer->handle = handle; | |||||
initCallback(manufacturer); | |||||
// Construct and initialize Plugin instance | |||||
Plugin *plugin = new Plugin(); | |||||
plugin->path = path; | |||||
plugin->handle = handle; | |||||
initCallback(plugin); | |||||
// Check that this is a unique slug | |||||
for (Manufacturer *otherManufacturer : gManufacturers) { | |||||
assert(manufacturer->slug != otherManufacturer->slug); | |||||
} | |||||
// Add manufacturer to list | |||||
gManufacturers.push_back(manufacturer); | |||||
// Add plugin to list | |||||
gPlugins.push_back(plugin); | |||||
fprintf(stderr, "Loaded plugin %s\n", libraryFilename.c_str()); | fprintf(stderr, "Loaded plugin %s\n", libraryFilename.c_str()); | ||||
return 0; | return 0; | ||||
} | } | ||||
@@ -200,13 +195,6 @@ static void refreshPurchase(json_t *pluginJ) { | |||||
url += "&token="; | url += "&token="; | ||||
url += gToken; | url += gToken; | ||||
// Find slug in plugins list, and return silently if slug already exists | |||||
for (Manufacturer *m : gManufacturers) { | |||||
if (m->slug == slug) { | |||||
return; | |||||
} | |||||
} | |||||
// If plugin is not loaded, download the zip file to /plugins | // If plugin is not loaded, download the zip file to /plugins | ||||
downloadName = name; | downloadName = name; | ||||
downloadProgress = 0.0; | downloadProgress = 0.0; | ||||
@@ -237,9 +225,9 @@ static void refreshPurchase(json_t *pluginJ) { | |||||
void pluginInit() { | void pluginInit() { | ||||
// Load core | // Load core | ||||
// This function is defined in core.cpp | // This function is defined in core.cpp | ||||
Manufacturer *coreManufacturer = new Manufacturer(); | |||||
Plugin *coreManufacturer = new Plugin(); | |||||
init(coreManufacturer); | init(coreManufacturer); | ||||
gManufacturers.push_back(coreManufacturer); | |||||
gPlugins.push_back(coreManufacturer); | |||||
// Load plugins from global directory | // Load plugins from global directory | ||||
std::string globalPlugins = assetGlobal("plugins"); | std::string globalPlugins = assetGlobal("plugins"); | ||||
@@ -248,27 +236,29 @@ void pluginInit() { | |||||
// Load plugins from local directory | // Load plugins from local directory | ||||
std::string localPlugins = assetLocal("plugins"); | std::string localPlugins = assetLocal("plugins"); | ||||
mkdir(localPlugins.c_str(), 0755); | |||||
printf("Loading plugins from %s\n", localPlugins.c_str()); | |||||
if (globalPlugins != localPlugins) | |||||
if (globalPlugins != localPlugins) { | |||||
mkdir(localPlugins.c_str(), 0755); | |||||
printf("Loading plugins from %s\n", localPlugins.c_str()); | |||||
loadPlugins(localPlugins); | loadPlugins(localPlugins); | ||||
} | |||||
} | } | ||||
void pluginDestroy() { | void pluginDestroy() { | ||||
for (Manufacturer *manufacturer : gManufacturers) { | |||||
for (Plugin *plugin : gPlugins) { | |||||
// Free library handle | // Free library handle | ||||
#if ARCH_WIN | #if ARCH_WIN | ||||
if (manufacturer->handle) | |||||
FreeLibrary((HINSTANCE)manufacturer->handle); | |||||
if (plugin->handle) | |||||
FreeLibrary((HINSTANCE)plugin->handle); | |||||
#elif ARCH_LIN || ARCH_MAC | #elif ARCH_LIN || ARCH_MAC | ||||
if (manufacturer->handle) | |||||
dlclose(manufacturer->handle); | |||||
if (plugin->handle) | |||||
dlclose(plugin->handle); | |||||
#endif | #endif | ||||
// For some reason this segfaults | |||||
// delete manufacturer; | |||||
// For some reason this segfaults. | |||||
// It might be best to let them leak anyway, because "crash on exit" issues would occur with badly-written plugins. | |||||
// delete plugin; | |||||
} | } | ||||
gManufacturers.clear(); | |||||
gPlugins.clear(); | |||||
} | } | ||||
void pluginLogIn(std::string email, std::string password) { | void pluginLogIn(std::string email, std::string password) { | ||||