diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Fl_Preferences.cxx | 205 |
1 files changed, 200 insertions, 5 deletions
diff --git a/src/Fl_Preferences.cxx b/src/Fl_Preferences.cxx index 8864604a6..d29a1b6b8 100644 --- a/src/Fl_Preferences.cxx +++ b/src/Fl_Preferences.cxx @@ -28,6 +28,7 @@ #include <FL/Fl.H> #include <FL/Fl_Preferences.H> +#include <FL/Fl_Plugin.H> #include <FL/Fl_Tree.H> #include <FL/filename.H> @@ -40,6 +41,7 @@ #include <time.h> #if defined(WIN32) && !defined(__CYGWIN__) +# include <windows.h> # include <direct.h> # include <io.h> // Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs @@ -49,8 +51,10 @@ #elif defined (__APPLE__) # include <Carbon/Carbon.h> # include <unistd.h> +# include <dlfcn.h> #else # include <unistd.h> +# include <dlfcn.h> #endif #ifdef WIN32 @@ -65,6 +69,7 @@ typedef RPC_STATUS (WINAPI* uuid_func)(UUID __RPC_FAR *Uuid); char Fl_Preferences::nameBuffer[128]; char Fl_Preferences::uuidBuffer[40]; +Fl_Preferences *Fl_Preferences::runtimePrefs = 0; /** * Returns a UUID as generated by the system. @@ -198,8 +203,13 @@ const char *Fl_Preferences::newUUID() name of your application. Both vendor and application must be valid relative UNIX pathnames and may contain '/'s to create deeper file structures. + + A set of Preferences marked "run-time" exists exactly one per application and + only as long as the application runs. It can be used as a database for + volatile information. FLTK uses it to register plugins at run-time. - \param[in] root can be \c USER or \c SYSTEM for user specific or system wide preferences + \param[in] root can be \c USER or \c SYSTEM for user specific or system wide + preferences \param[in] vendor unique text describing the company or author of this file \param[in] application unique text describing the application */ @@ -249,10 +259,26 @@ Fl_Preferences::Fl_Preferences( Fl_Preferences &parent, const char *group ) /** + \brief Create or access a group of preferences using a name. + \param[in] parent the parameter parent is a pointer to the parent group. + \p Parent may be \p NULL. It then refers to an application internal + database which exists only once, and remains in RAM only until the + application quits. This databse is used to manage plugins and other + data indexes by strings. + \param[in] group a group name that is used as a key into the databse \see Fl_Preferences( Fl_Preferences&, const char *group ) */ Fl_Preferences::Fl_Preferences( Fl_Preferences *parent, const char *group ) { + if (parent==0) { + if (!runtimePrefs) { + runtimePrefs = new Fl_Preferences(); + runtimePrefs->node = new Node( "." ); + runtimePrefs->rootNode = new RootNode( runtimePrefs ); + runtimePrefs->node->setRoot(rootNode); + } + parent = runtimePrefs; + } rootNode = parent->rootNode; node = parent->node->addChild( group ); } @@ -313,6 +339,25 @@ Fl_Preferences::Fl_Preferences( Fl_Preferences::ID id ) rootNode = node->findRoot(); } +/** + Create another reference to a Preferences group. + */ +Fl_Preferences::Fl_Preferences(const Fl_Preferences &rhs) +: node(rhs.node), + rootNode(rhs.rootNode) +{ } + +/** + Assign another reference to a Preference group. + */ +Fl_Preferences &Fl_Preferences::operator=(const Fl_Preferences &rhs) { + if (&rhs != this) { + node = rhs.node; + rootNode = rhs.rootNode; + } + return *this; +} + /** The destructor removes allocated resources. When used on the @@ -1025,6 +1070,10 @@ static void makePathForFile( const char *path ) // create the root node // - construct the name of the file that will hold our preferences Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char *vendor, const char *application ) +: prefs_(prefs), + filename_(0L), + vendor_(0L), + application_(0L) { char filename[ FL_PATH_MAX ]; filename[0] = 0; #ifdef WIN32 @@ -1141,7 +1190,6 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char "%s/%s.prefs", vendor, application); #endif - prefs_ = prefs; filename_ = strdup(filename); vendor_ = strdup(vendor); application_ = strdup(application); @@ -1152,6 +1200,10 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, Root root, const char // create the root node // - construct the name of the file that will hold our preferences Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, const char *vendor, const char *application ) +: prefs_(prefs), + filename_(0L), + vendor_(0L), + application_(0L) { if (!vendor) vendor = "unknown"; @@ -1163,13 +1215,22 @@ Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs, const char *path, con snprintf(filename, sizeof(filename), "%s/%s.prefs", path, application); filename_ = strdup(filename); } - prefs_ = prefs; vendor_ = strdup(vendor); application_ = strdup(application); read(); } +// create a root node that exists only on RAM and can not be read or written to +// a file +Fl_Preferences::RootNode::RootNode( Fl_Preferences *prefs ) +: prefs_(prefs), + filename_(0L), + vendor_(0L), + application_(0L) +{ +} + // destroy the root node and all depending nodes Fl_Preferences::RootNode::~RootNode() { @@ -1194,9 +1255,14 @@ Fl_Preferences::RootNode::~RootNode() // read a preferences file and construct the group tree and with all entry leafs int Fl_Preferences::RootNode::read() { + if (!filename_) // RUNTIME preferences + return -1; + char buf[1024]; FILE *f = fl_fopen( filename_, "rb" ); - if ( !f ) return 0; + if ( !f ) + return -1; + fgets( buf, 1024, f ); fgets( buf, 1024, f ); fgets( buf, 1024, f ); @@ -1236,9 +1302,14 @@ int Fl_Preferences::RootNode::read() // write the group tree and all entry leafs int Fl_Preferences::RootNode::write() { + if (!filename_) // RUNTIME preferences + return -1; + fl_make_path_for_file(filename_); FILE *f = fl_fopen( filename_, "wb" ); - if ( !f ) return 1; + if ( !f ) + return -1; + fprintf( f, "; FLTK preferences file format 1.0\n" ); fprintf( f, "; vendor: %s\n", vendor_ ); fprintf( f, "; application: %s\n", application_ ); @@ -1250,6 +1321,9 @@ int Fl_Preferences::RootNode::write() // get the path to the preferences directory char Fl_Preferences::RootNode::getPath( char *path, int pathlen ) { + if (!filename_) // RUNTIME preferences + return -1; + strlcpy( path, filename_, pathlen); char *s; @@ -1673,6 +1747,127 @@ char Fl_Preferences::Node::copyTo(Fl_Tree *tree, Fl_Tree_Item *ti) return 0; } + +/** + * \brief Create a plugin. + * + * \param[in] klass plugins are grouped in classes + * \param[in] name every plugin should have a unique name + */ +Fl_Plugin::Fl_Plugin(const char *klass, const char *name) +: id(0) +{ + Fl_Plugin_Manager pm(klass); + id = pm.addPlugin(name, this); +} + +/** + * \brief Clear the plugin and remove it from the database. + */ +Fl_Plugin::~Fl_Plugin() +{ + if (id) + Fl_Plugin_Manager::remove(id); +} + + +/** + * \brief Manage all plugins belonging to one class. + */ +Fl_Plugin_Manager::Fl_Plugin_Manager(const char *klass) +: Fl_Preferences(0, Fl_Preferences::Name("%s/%s", "plugins", klass)) +{ +} + +/** + * \brief Remove the plugin manager. + * + * Calling this does not remove the database itself or any plugins. It just + * removes the reference to the database. + */ +Fl_Plugin_Manager::~Fl_Plugin_Manager() +{ +} + +/** + * \brief Return the address of a plugin by index. + */ +Fl_Plugin *Fl_Plugin_Manager::plugin(int index) +{ + char buf[32]; + Fl_Plugin *ret = 0; + Fl_Preferences pin(this, index); + pin.get("address", buf, "@0", 32); + sscanf(buf, "@%p", &ret); + return ret; +} + +/** + * \brief This function adds a new plugin to the databse. + * + * There is no need to call this function explicitly. Every Fl_Plugin constructor + * will call this function at initialization time. + */ +Fl_Preferences::ID Fl_Plugin_Manager::addPlugin(const char *name, Fl_Plugin *plugin) +{ + char buf[32]; + Fl_Preferences pin(this, name); + snprintf(buf, 32, "@%p", plugin); + pin.set("address", buf); + return pin.id(); +} + +/** + * \brief Remove any plugin. + * + * There is no need to call this function explicitly. Every Fl_Plugin destructor + * will call this function at destruction time. + */ +void Fl_Plugin_Manager::removePlugin(Fl_Preferences::ID id) +{ + Fl_Preferences::remove(id); +} + +/** + * \brief Load a module from disk. + * + * A module must be a dynamically linkable file for the given operating system. + * When loading a module, its +init function will be called which in turn calls + * the constructor of all statically initialized Fl_Plugin classes and adds + * them to the database. + */ +int Fl_Plugin_Manager::load(const char *filename) +{ + // the functions below will autmaticaly load plugins that are defined: + // Fl_My_Plugin plugin(); +#ifdef WIN32 + HMODULE dl = LoadLibrary(filename); +#else + void * dl = dlopen(filename, RTLD_LAZY); +#endif + // There is no way of unloading a plugin! + return (dl!=0) ? 0 : -1; +} + +/** + * \brief Use this function to load a whole directory full of modules. + */ +int Fl_Plugin_Manager::loadAll(const char *filepath, const char *pattern) +{ + struct dirent **dir; + int i, n = fl_filename_list(filepath, &dir); + for (i=0; i<n; i++) { + struct dirent *e = dir[i]; + if (pattern==0 || fl_filename_match(e->d_name, pattern)) { + load(Fl_Preferences::Name("%s%s", filepath, e->d_name)); + } + free(e); + } + free(dir); + return 0; +} + + // // End of "$Id$". // |
