summaryrefslogtreecommitdiff
path: root/src/plugin.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugin.cpp')
-rw-r--r--src/plugin.cpp780
1 files changed, 780 insertions, 0 deletions
diff --git a/src/plugin.cpp b/src/plugin.cpp
new file mode 100644
index 0000000..d545240
--- /dev/null
+++ b/src/plugin.cpp
@@ -0,0 +1,780 @@
+/*
+ * Copyright © 2005 Novell, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of
+ * Novell, Inc. not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior permission.
+ * Novell, Inc. makes no representations about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ *
+ * NOVELL, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL NOVELL, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Author: David Reveman <davidr@novell.com>
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dlfcn.h>
+#include <dirent.h>
+
+#include <compiz-core.h>
+
+CompPlugin *plugins = 0;
+
+static Bool
+coreInit (CompPlugin *p)
+{
+ return TRUE;
+}
+
+static void
+coreFini (CompPlugin *p)
+{
+}
+
+static CompMetadata *
+coreGetMetadata (CompPlugin *plugin)
+{
+ return &coreMetadata;
+}
+
+static CompOption *
+coreGetObjectOptions (CompPlugin *plugin,
+ CompObject *object,
+ int *count)
+{
+ static GetPluginObjectOptionsProc dispTab[] = {
+ (GetPluginObjectOptionsProc) 0, /* GetCoreOptions */
+ (GetPluginObjectOptionsProc) getDisplayOptions,
+ (GetPluginObjectOptionsProc) getScreenOptions
+ };
+
+ RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab),
+ (CompOption *) (*count = 0), (plugin, object, count));
+}
+
+static Bool
+coreSetObjectOption (CompPlugin *plugin,
+ CompObject *object,
+ const char *name,
+ CompOptionValue *value)
+{
+ static SetPluginObjectOptionProc dispTab[] = {
+ (SetPluginObjectOptionProc) 0, /* SetCoreOption */
+ (SetPluginObjectOptionProc) setDisplayOption,
+ (SetPluginObjectOptionProc) setScreenOption
+ };
+
+ RETURN_DISPATCH (object, dispTab, ARRAY_SIZE (dispTab), FALSE,
+ (plugin, object, name, value));
+}
+
+static CompPluginVTable coreVTable = {
+ "core",
+ coreGetMetadata,
+ coreInit,
+ coreFini,
+ 0, /* InitObject */
+ 0, /* FiniObject */
+ coreGetObjectOptions,
+ coreSetObjectOption
+};
+
+static Bool
+cloaderLoadPlugin (CompPlugin *p,
+ const char *path,
+ const char *name)
+{
+ if (path)
+ return FALSE;
+
+ if (strcmp (name, coreVTable.name))
+ return FALSE;
+
+ p->vTable = &coreVTable;
+ p->devPrivate.ptr = NULL;
+ p->devType = "cloader";
+
+ return TRUE;
+}
+
+static void
+cloaderUnloadPlugin (CompPlugin *p)
+{
+}
+
+static char **
+cloaderListPlugins (const char *path,
+ int *n)
+{
+ char **list;
+
+ if (path)
+ return 0;
+
+ list = (char **) malloc (sizeof (char *));
+ if (!list)
+ return 0;
+
+ *list = strdup (coreVTable.name);
+ if (!*list)
+ {
+ free (list);
+ return 0;
+ }
+
+ *n = 1;
+
+ return list;
+}
+
+static Bool
+dlloaderLoadPlugin (CompPlugin *p,
+ const char *path,
+ const char *name)
+{
+ char *file;
+ void *dlhand;
+
+ file = (char *) malloc ((path ? strlen (path) : 0) + strlen (name) + 8);
+ if (!file)
+ return FALSE;
+
+ if (path)
+ sprintf (file, "%s/lib%s.so", path, name);
+ else
+ sprintf (file, "lib%s.so", name);
+
+ dlhand = dlopen (file, RTLD_LAZY);
+ if (dlhand)
+ {
+ PluginGetInfoProc getInfo;
+ char *error;
+
+ dlerror ();
+
+ getInfo = (PluginGetInfoProc)
+ dlsym (dlhand, "getCompPluginInfo20070830");
+
+ error = dlerror ();
+ if (error)
+ {
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "dlsym: %s", error);
+
+ getInfo = 0;
+ }
+
+ if (getInfo)
+ {
+ p->vTable = (*getInfo) ();
+ if (!p->vTable)
+ {
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "Couldn't get vtable from '%s' plugin",
+ file);
+
+ dlclose (dlhand);
+ free (file);
+
+ return FALSE;
+ }
+ }
+ else
+ {
+ dlclose (dlhand);
+ free (file);
+
+ return FALSE;
+ }
+ }
+ else
+ {
+ free (file);
+
+ return cloaderLoadPlugin (p, path, name);
+ }
+
+ free (file);
+
+ p->devPrivate.ptr = dlhand;
+ p->devType = "dlloader";
+
+ return TRUE;
+}
+
+static void
+dlloaderUnloadPlugin (CompPlugin *p)
+{
+ if (strcmp (p->devType, "dlloader") == 0)
+ dlclose (p->devPrivate.ptr);
+ else
+ cloaderUnloadPlugin (p);
+}
+
+static int
+dlloaderFilter (const struct dirent *name)
+{
+ int length = strlen (name->d_name);
+
+ if (length < 7)
+ return 0;
+
+ if (strncmp (name->d_name, "lib", 3) ||
+ strncmp (name->d_name + length - 3, ".so", 3))
+ return 0;
+
+ return 1;
+}
+
+static char **
+dlloaderListPlugins (const char *path,
+ int *n)
+{
+ struct dirent **nameList;
+ char **list, **cList;
+ char *name;
+ int length, nFile, i, j = 0;
+
+ cList = cloaderListPlugins (path, n);
+ if (cList)
+ j = *n;
+
+ if (!path)
+ path = ".";
+
+ nFile = scandir (path, &nameList, dlloaderFilter, alphasort);
+ if (!nFile)
+ return cList;
+
+ list = (char **) realloc (cList, (j + nFile) * sizeof (char *));
+ if (!list)
+ return cList;
+
+ for (i = 0; i < nFile; i++)
+ {
+ length = strlen (nameList[i]->d_name);
+
+ name = (char *) malloc ((length - 5) * sizeof (char));
+ if (name)
+ {
+ strncpy (name, nameList[i]->d_name + 3, length - 6);
+ name[length - 6] = '\0';
+
+ list[j++] = name;
+ }
+ }
+
+ if (j)
+ {
+ *n = j;
+
+ return list;
+ }
+
+ free (list);
+
+ return NULL;
+}
+
+LoadPluginProc loaderLoadPlugin = dlloaderLoadPlugin;
+UnloadPluginProc loaderUnloadPlugin = dlloaderUnloadPlugin;
+ListPluginsProc loaderListPlugins = dlloaderListPlugins;
+
+typedef struct _InitObjectContext {
+ CompPlugin *plugin;
+ CompObject *object;
+} InitObjectContext;
+
+typedef struct _InitObjectTypeContext {
+ CompPlugin *plugin;
+ CompObjectType type;
+} InitObjectTypeContext;
+
+static CompBool
+initObjectTree (CompObject *object,
+ void *closure);
+
+static CompBool
+finiObjectTree (CompObject *object,
+ void *closure);
+
+static CompBool
+initObjectsWithType (CompObjectType type,
+ CompObject *parent,
+ void *closure)
+{
+ InitObjectTypeContext *pCtx = (InitObjectTypeContext *) closure;
+ InitObjectContext ctx;
+
+ pCtx->type = type;
+
+ ctx.plugin = pCtx->plugin;
+ ctx.object = NULL;
+
+ if (!compObjectForEach (parent, type, initObjectTree, (void *) &ctx))
+ {
+ compObjectForEach (parent, type, finiObjectTree, (void *) &ctx);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static CompBool
+finiObjectsWithType (CompObjectType type,
+ CompObject *parent,
+ void *closure)
+{
+ InitObjectTypeContext *pCtx = (InitObjectTypeContext *) closure;
+ InitObjectContext ctx;
+
+ /* pCtx->type is set to the object type that failed to be initialized */
+ if (pCtx->type == type)
+ return FALSE;
+
+ ctx.plugin = pCtx->plugin;
+ ctx.object = NULL;
+
+ compObjectForEach (parent, type, finiObjectTree, (void *) &ctx);
+
+ return TRUE;
+}
+
+static CompBool
+initObjectTree (CompObject *object,
+ void *closure)
+{
+ InitObjectContext *pCtx = (InitObjectContext *) closure;
+ CompPlugin *p = pCtx->plugin;
+ InitObjectTypeContext ctx;
+
+ pCtx->object = object;
+
+ if (p->vTable->initObject)
+ {
+ if (!(*p->vTable->initObject) (p, object))
+ {
+ compLogMessage (NULL, p->vTable->name, CompLogLevelError,
+ "InitObject failed");
+ return FALSE;
+ }
+ }
+
+ ctx.plugin = p;
+ ctx.type = 0;
+
+ /* initialize children */
+ if (!compObjectForEachType (object, initObjectsWithType, (void *) &ctx))
+ {
+ compObjectForEachType (object, finiObjectsWithType, (void *) &ctx);
+
+ if (p->vTable->initObject && p->vTable->finiObject)
+ (*p->vTable->finiObject) (p, object);
+
+ return FALSE;
+ }
+
+ if (!(*core.initPluginForObject) (p, object))
+ {
+ compObjectForEachType (object, finiObjectsWithType, (void *) &ctx);
+
+ if (p->vTable->initObject && p->vTable->finiObject)
+ (*p->vTable->finiObject) (p, object);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static CompBool
+finiObjectTree (CompObject *object,
+ void *closure)
+{
+ InitObjectContext *pCtx = (InitObjectContext *) closure;
+ CompPlugin *p = pCtx->plugin;
+ InitObjectTypeContext ctx;
+
+ /* pCtx->object is set to the object that failed to be initialized */
+ if (pCtx->object == object)
+ return FALSE;
+
+ ctx.plugin = p;
+ ctx.type = ~0;
+
+ compObjectForEachType (object, finiObjectsWithType, (void *) &ctx);
+
+ if (p->vTable->initObject && p->vTable->finiObject)
+ (*p->vTable->finiObject) (p, object);
+
+ (*core.finiPluginForObject) (p, object);
+
+ return TRUE;
+}
+
+static Bool
+initPlugin (CompPlugin *p)
+{
+ InitObjectContext ctx;
+
+ if (!(*p->vTable->init) (p))
+ {
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "InitPlugin '%s' failed", p->vTable->name);
+ return FALSE;
+ }
+
+ ctx.plugin = p;
+ ctx.object = NULL;
+
+ if (!initObjectTree (&core.base, (void *) &ctx))
+ {
+ (*p->vTable->fini) (p);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+finiPlugin (CompPlugin *p)
+{
+ InitObjectContext ctx;
+
+ ctx.plugin = p;
+ ctx.object = NULL;
+
+ finiObjectTree (&core.base, (void *) &ctx);
+
+ (*p->vTable->fini) (p);
+}
+
+CompBool
+objectInitPlugins (CompObject *o)
+{
+ InitObjectContext ctx;
+ CompPlugin *p;
+ int i, j = 0;
+
+ ctx.object = NULL;
+
+ for (p = plugins; p; p = p->next)
+ j++;
+
+ while (j--)
+ {
+ i = 0;
+ for (p = plugins; i < j; p = p->next)
+ i++;
+
+ ctx.plugin = p;
+
+ if (!initObjectTree (o, (void *) &ctx))
+ {
+ for (p = p->next; p; p = p->next)
+ {
+ ctx.plugin = p;
+
+ finiObjectTree (o, (void *) &ctx);
+ }
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+void
+objectFiniPlugins (CompObject *o)
+{
+ InitObjectContext ctx;
+ CompPlugin *p;
+
+ ctx.object = NULL;
+
+ for (p = plugins; p; p = p->next)
+ {
+ ctx.plugin = p;
+
+ finiObjectTree (o, (void *) &ctx);
+ }
+}
+
+CompPlugin *
+findActivePlugin (const char *name)
+{
+ CompPlugin *p;
+
+ for (p = plugins; p; p = p->next)
+ {
+ if (strcmp (p->vTable->name, name) == 0)
+ return p;
+ }
+
+ return 0;
+}
+
+void
+unloadPlugin (CompPlugin *p)
+{
+ (*loaderUnloadPlugin) (p);
+ free (p);
+}
+
+CompPlugin *
+loadPlugin (const char *name)
+{
+ CompPlugin *p;
+ char *home, *plugindir;
+ Bool status;
+
+ p = (CompPlugin *) malloc (sizeof (CompPlugin));
+ if (!p)
+ return 0;
+
+ p->next = 0;
+ p->devPrivate.uval = 0;
+ p->devType = NULL;
+ p->vTable = 0;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ plugindir = (char *) malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR);
+ status = (*loaderLoadPlugin) (p, plugindir, name);
+ free (plugindir);
+
+ if (status)
+ return p;
+ }
+ }
+
+ status = (*loaderLoadPlugin) (p, PLUGINDIR, name);
+ if (status)
+ return p;
+
+ status = (*loaderLoadPlugin) (p, NULL, name);
+ if (status)
+ return p;
+
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "Couldn't load plugin '%s'", name);
+
+ return 0;
+}
+
+Bool
+pushPlugin (CompPlugin *p)
+{
+ if (findActivePlugin (p->vTable->name))
+ {
+ compLogMessage (NULL, "core", CompLogLevelWarn,
+ "Plugin '%s' already active",
+ p->vTable->name);
+
+ return FALSE;
+ }
+
+ p->next = plugins;
+ plugins = p;
+
+ if (!initPlugin (p))
+ {
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "Couldn't activate plugin '%s'", p->vTable->name);
+ plugins = p->next;
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+CompPlugin *
+popPlugin (void)
+{
+ CompPlugin *p = plugins;
+
+ if (!p)
+ return 0;
+
+ finiPlugin (p);
+
+ plugins = p->next;
+
+ return p;
+}
+
+CompPlugin *
+getPlugins (void)
+{
+ return plugins;
+}
+
+static Bool
+stringExist (char **list,
+ int nList,
+ char *s)
+{
+ int i;
+
+ for (i = 0; i < nList; i++)
+ if (strcmp (list[i], s) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+char **
+availablePlugins (int *n)
+{
+ char *home, *plugindir;
+ char **list, **currentList, **pluginList, **homeList = NULL;
+ int nCurrentList, nPluginList, nHomeList;
+ int count, i, j;
+
+ home = getenv ("HOME");
+ if (home)
+ {
+ plugindir = (char *) malloc (strlen (home) + strlen (HOME_PLUGINDIR) + 3);
+ if (plugindir)
+ {
+ sprintf (plugindir, "%s/%s", home, HOME_PLUGINDIR);
+ homeList = (*loaderListPlugins) (plugindir, &nHomeList);
+ free (plugindir);
+ }
+ }
+
+ pluginList = (*loaderListPlugins) (PLUGINDIR, &nPluginList);
+ currentList = (*loaderListPlugins) (NULL, &nCurrentList);
+
+ count = 0;
+ if (homeList)
+ count += nHomeList;
+ if (pluginList)
+ count += nPluginList;
+ if (currentList)
+ count += nCurrentList;
+
+ if (!count)
+ return NULL;
+
+ list = (char **) malloc (count * sizeof (char *));
+ if (!list)
+ return NULL;
+
+ j = 0;
+ if (homeList)
+ {
+ for (i = 0; i < nHomeList; i++)
+ if (!stringExist (list, j, homeList[i]))
+ list[j++] = homeList[i];
+
+ free (homeList);
+ }
+
+ if (pluginList)
+ {
+ for (i = 0; i < nPluginList; i++)
+ if (!stringExist (list, j, pluginList[i]))
+ list[j++] = pluginList[i];
+
+ free (pluginList);
+ }
+
+ if (currentList)
+ {
+ for (i = 0; i < nCurrentList; i++)
+ if (!stringExist (list, j, currentList[i]))
+ list[j++] = currentList[i];
+
+ free (currentList);
+ }
+
+ *n = j;
+
+ return list;
+}
+
+int
+getPluginABI (const char *name)
+{
+ CompPlugin *p = findActivePlugin (name);
+ CompOption *option;
+ int nOption;
+
+ if (!p || !p->vTable->getObjectOptions)
+ return 0;
+
+ /* MULTIDPYERROR: ABI options should be moved into core */
+ option = (*p->vTable->getObjectOptions) (p, &core.displays->base,
+ &nOption);
+
+ return getIntOptionNamed (option, nOption, "abi", 0);
+}
+
+Bool
+checkPluginABI (const char *name,
+ int abi)
+{
+ int pluginABI;
+
+ pluginABI = getPluginABI (name);
+ if (!pluginABI)
+ {
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "Plugin '%s' not loaded.\n", name);
+ return FALSE;
+ }
+ else if (pluginABI != abi)
+ {
+ compLogMessage (NULL, "core", CompLogLevelError,
+ "Plugin '%s' has ABI version '%d', expected "
+ "ABI version '%d'.\n",
+ name, pluginABI, abi);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+Bool
+getPluginDisplayIndex (CompDisplay *d,
+ const char *name,
+ int *index)
+{
+ CompPlugin *p = findActivePlugin (name);
+ CompOption *option;
+ int nOption, value;
+
+ if (!p || !p->vTable->getObjectOptions)
+ return FALSE;
+
+ option = (*p->vTable->getObjectOptions) (p, &d->base, &nOption);
+
+ value = getIntOptionNamed (option, nOption, "index", -1);
+ if (value < 0)
+ return FALSE;
+
+ *index = value;
+
+ return TRUE;
+}