Logo Search packages:      
Sourcecode: beryl-core version File versions

main.c

/*
 *
 * Copyright : (C) 2007 Quinn Storm
 * E-mail    : quinn@beryl-project.org
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 */

//LIBBERYLSETTINGS
//SO VERSION 0
//see spec in header
#define _GNU_SOURCE
#include <stdlib.h>
#include <beryl-settings.h>
#include <string.h>
#include <malloc.h>
#include <libintl.h>
#include <dlfcn.h>
#include <beryl.h>

CompDisplay *display = NULL;
static char *codeset = NULL;

typedef enum
{
      OPT_BACKEND,
      OPT_PROFILE,
      OPT_INTEGRATION,
} generalOption;

#define NEW(a,b) \
      a * b = malloc(sizeof(a)); memset((b),0,sizeof(a))

static const BerylSettingsPluginCategory PluginCategories[] =
{
      {"wm",                        N_("Window Management"),      N_("Plugins that provide window management related functionality"),           NULL},
      {"desktop",             N_("Desktop"),                      N_("Plugins related to the desktop in general"),                                    NULL},
      {"effects",             N_("Visual Effects"),         N_("Plugins that provide visual effects"),                                                NULL},
      {"accessibility", N_("Accessibility"),          N_("Plugins that provide accessibility features"),                                  NULL},
      {"misc",                N_("Extras"),                       N_("Plugins for less commonly used features"),                                      NULL},
      {"devel",               N_("Development"),                  N_("Plugins generally only useful to developers"),                                  NULL},
      {"imageformat",         N_("Image Format"),                 N_("Plugins that provide loading and saving for various image formats"),NULL},
      {"settings",            N_("Settings Plugins"),       N_("These plugins provide settings management"),                                    NULL},
      {"",                    N_("Unknown Category"),       N_("These plugins are in an as-yet unknown category"),                              NULL},
};

static const int nPluginCategories = sizeof(PluginCategories)/sizeof(PluginCategories[0]);

GSList * Backends = NULL;

gboolean backends_need_init = TRUE;

typedef const gchar * (*BSBDescFunc) (void);
typedef gboolean (*BSBIntegFunc) (void);

//static SubGroupDesc coreBindingsGroupDesc[]={
//    {"Foo","Bar"},
//};

//static GroupDesc coreGroupDescs[]=
//{
//    {"Bindings",      N_("Bindings"),   coreBindingsGroupDesc, sizeof(coreBindingsGroupDesc)/sizeof(SubGroupDesc)},
//};

static GroupDesc coreGroupDescs[1];

static const int nCoreGroupDescs=0;
//sizeof(coreGroupDescs)/sizeof(coreGroupDescs[0]);

struct _Modifier {
      gchar *name;
      gint  modifier;
} const static modifiers[] = {
      { "<Shift>",      ShiftMask          },
      { "<Control>",    ControlMask  },
      { "<Mod1>",       Mod1Mask           },
      { "<Mod2>",       Mod2Mask           },
      { "<Mod3>",       Mod3Mask           },
      { "<Mod4>",       Mod4Mask           },
      { "<Mod5>",       Mod5Mask           },
      { "<Alt>",        CompAltMask        },
      { "<Meta>",       CompMetaMask       },
      { "<Super>",      CompSuperMask      },
      { "<Hyper>",      CompHyperMask      },
      { "<ModeSwitch>", CompModeSwitchMask },
};

#define N_MODIFIERS (sizeof (modifiers) / sizeof (struct _Modifier))

unsigned int beryl_settings_get_mods_and_endptr(gchar * src, gchar ** ret)
{
      unsigned int mods=0;
      gchar * spos=src;
      while((spos=strchr(spos,'<')) && *src)
      {
            int i;
            for (i=0;i<N_MODIFIERS;i++)
                  if (strncasecmp(modifiers[i].name,
                                    spos,strlen(modifiers[i].name))==0)
                  {
                        mods|=modifiers[i].modifier;
                        spos+=strlen(modifiers[i].name);
                        src=spos;
                        break;
                  }
            if (i==N_MODIFIERS)
                  break;
      }
      *ret=src;
      return mods;
}

gchar * beryl_settings_mods_to_string(unsigned int mods)
{
      gchar * retstr=g_strdup("");
      gchar * tmpstr=retstr;
      gint i;
      for (i=0;i<N_MODIFIERS;i++)
      {
            if (mods & modifiers[i].modifier)
            {
                  retstr=g_strconcat(retstr,modifiers[i].name,NULL);
                  g_free(tmpstr);
                  tmpstr=retstr;
            }
      }
      return retstr;
}

//STATIC FUNCTIONS
static void copy_value(BerylSettingValue * dest, BerylSettingValue * src)
{
      BerylSettingType type;
      if (src->is_list_child)
            type=src->parent->info.for_list.list_of_type;
      else
            type=src->parent->type;
      dest->parent=src->parent;
      dest->is_list_child=src->is_list_child;
      if (type != BERYL_SETTING_TYPE_LIST)
      {
            if (type != BERYL_SETTING_TYPE_STRING)
                  memcpy(&dest->value,&src->value,sizeof(BerylSettingValueUnion));
            else
                  dest->value.as_string=g_strdup(src->value.as_string);
      }
      else
      {
            GSList * newsrc;
            dest->value.as_list=NULL;
            for (newsrc=src->value.as_list;newsrc;newsrc=newsrc->next)
            {
                  NEW(BerylSettingValue,newdest);
                  copy_value(newdest,newsrc->data);
                  dest->value.as_list=g_slist_append(dest->value.as_list,newdest);
            }
      }
}

static void copy_from_default(BerylSetting * setting)
{
      copy_value(&setting->value,&setting->default_value);
}


static void init_info(BerylSettingInfo * info, CompOption * o, BerylSettingType type,
            gchar * gettext_domain)
{
      switch(type)
      {
            case BERYL_SETTING_TYPE_INT:
                  info->for_int.min=o->rest.i.min;
                  info->for_int.max=o->rest.i.max;
                  break;
            case BERYL_SETTING_TYPE_FLOAT:
                  info->for_float.min=o->rest.f.min;
                  info->for_float.max=o->rest.f.max;
                  info->for_float.precision=o->rest.f.precision;
                  break;
            case BERYL_SETTING_TYPE_STRING:
                  if (o->rest.s.nString && o->rest.s.string)
                  {
                        int i;
                        for (i=0;i<o->rest.s.nString;i++)
                        {
                              info->for_string.raw_values=g_slist_append(
                                          info->for_string.raw_values,g_strdup(o->rest.s.string[i]));
                              info->for_string.allowed_values=g_slist_append(
                                          info->for_string.allowed_values,
                                          g_strdup(dgettext(gettext_domain,o->rest.s.string[i])));
                        }
                  }
                  break;
            case BERYL_SETTING_TYPE_BINDING:
                  info->for_bind.key=(o->value.action.state &
                              CompActionStateInitKey) && TRUE;
                  info->for_bind.button=(o->value.action.state &
                              CompActionStateInitButton) && TRUE;
                  info->for_bind.edge=(o->value.action.state &
                              CompActionStateInitEdge) && TRUE;
                  info->for_bind.bell=(o->value.action.state &
                              CompActionStateInitBell) && TRUE;
                  break;
            default:
                  break;
      }
}

static void init_value(BerylSettingValue * value, CompOptionValue * from, BerylSettingType type,
            gchar * gettext_domain)
{
      switch(type)
      {
            case BERYL_SETTING_TYPE_INT:
                  value->value.as_int=from->i;
                  break;
            case BERYL_SETTING_TYPE_FLOAT:
                  value->value.as_float=from->f;
                  break;
            case BERYL_SETTING_TYPE_BOOL:
                  value->value.as_bool=from->b;
                  break;
            case BERYL_SETTING_TYPE_COLOR:
                  {
                        int i;
                        for (i=0;i<4;i++)
                              value->value.as_color.array.array[i]=from->c[i];
                  }
                  break;
            case BERYL_SETTING_TYPE_STRING:
                  value->value.as_string=g_strdup(from->s);
                  break;
            case BERYL_SETTING_TYPE_BINDING:
                  value->value.as_binding.enabled.value.key=(from->action.type &
                              CompBindingTypeKey)?TRUE:FALSE;
                  value->value.as_binding.enabled.value.button=(from->action.type &
                              CompBindingTypeButton)?TRUE:FALSE;
                  value->value.as_binding.button=from->action.button.button;
                  value->value.as_binding.button_mod_mask=from->action.button.modifiers;
                  value->value.as_binding.keysym=from->action.key.keysym;
                  value->value.as_binding.key_mod_mask=from->action.key.modifiers;
                  value->value.as_binding.on_bell=from->action.bell;
                  value->value.as_binding.edge_mask=from->action.edgeMask;
                  break;
            default:
                  break;
      }
}

static BerylSettingType translate_type(CompOptionType type)
{
      switch(type)
      {
            case CompOptionTypeInt:
                  return BERYL_SETTING_TYPE_INT;
            case CompOptionTypeFloat:
                  return BERYL_SETTING_TYPE_FLOAT;
            case CompOptionTypeString:
                  return BERYL_SETTING_TYPE_STRING;
            case CompOptionTypeColor:
                  return BERYL_SETTING_TYPE_COLOR;
            case CompOptionTypeBool:
                  return BERYL_SETTING_TYPE_BOOL;
            case CompOptionTypeAction:
                  return BERYL_SETTING_TYPE_BINDING;
            case CompOptionTypeList:
                  return BERYL_SETTING_TYPE_LIST;
            default:
                  break;
      }
      return BERYL_SETTING_TYPE_COUNT;
}

static void init_option(BerylSettingsPlugin * plugin, CompOption * o, gboolean is_screen)
{
      NEW(BerylSetting,setting);
      setting->parent=plugin;
      setting->is_screen=is_screen;
      setting->is_default=TRUE;
      setting->name=g_strdup(o->name);
        if (codeset) {
                bind_textdomain_codeset (plugin->gettext_domain, codeset);
      }
      setting->short_desc=g_strdup(
                  dgettext(plugin->gettext_domain,o->shortDesc));
      setting->long_desc=g_strdup(dgettext(plugin->gettext_domain,o->longDesc));
      setting->group=g_strdup(strlen(o->group)?dgettext(plugin->gettext_domain,o->group):"");
      setting->subGroup=g_strdup(strlen(o->subGroup)?dgettext(plugin->gettext_domain,o->subGroup):"");
      setting->displayHints=g_strdup(o->displayHints);
      setting->type=translate_type(o->type);
      setting->advanced=o->advanced?TRUE:FALSE;
      setting->default_value.parent=setting;
      if (setting->type==BERYL_SETTING_TYPE_LIST)
      {
            NEW(BerylSettingInfo,list_info);
            setting->info.for_list.list_of_type=translate_type(o->value.list.type);
            setting->info.for_list.list_of_info=list_info;
            init_info(setting->info.for_list.list_of_info,o,
                        setting->info.for_list.list_of_type,plugin->gettext_domain);
            int i;
            for (i=0;i<o->value.list.nValue;i++)
            {
                  NEW(BerylSettingValue,val);
                  val->parent=setting;
                  val->is_list_child=TRUE;
                  init_value(val,&o->value.list.value[i],setting->info.for_list.list_of_type,
                              plugin->gettext_domain);
                  setting->default_value.value.as_list=
                        g_slist_append(setting->default_value.value.as_list,val);
            }
      }
      else
      {
            init_info(&setting->info,o,setting->type,plugin->gettext_domain);
            init_value(&setting->default_value,&o->value,setting->type,plugin->gettext_domain);
      }
      plugin->settings=g_slist_append(plugin->settings,setting);
      copy_from_default(setting);
}

static void comp_value_to_setting_value(CompOptionValue * comp_value, BerylSettingValue * beryl_value)
{
      BerylSettingType type;
      if (beryl_value->is_list_child)
            type=beryl_value->parent->info.for_list.list_of_type;
      else
            type=beryl_value->parent->type;
      beryl_value->parent->is_default=FALSE;
      switch(type)
      {
            case BERYL_SETTING_TYPE_INT:
                  beryl_value->value.as_int=comp_value->i;
                  break;
            case BERYL_SETTING_TYPE_FLOAT:
                  beryl_value->value.as_float=comp_value->f;
                  break;
            case BERYL_SETTING_TYPE_BOOL:
                  beryl_value->value.as_bool=comp_value->b;
                  break;
            case BERYL_SETTING_TYPE_COLOR:
                  {
                        int i;
                        for (i=0;i<4;i++)
                              beryl_value->value.as_color.array.array[i]=comp_value->c[i];
                  }
                  break;
            case BERYL_SETTING_TYPE_STRING:
                  if (beryl_value->value.as_string)
                        free(beryl_value->value.as_string);
                  beryl_value->value.as_string=g_strdup(comp_value->s);
                  break;
            case BERYL_SETTING_TYPE_BINDING:
                  beryl_value->value.as_binding.enabled.value.key =
                        (comp_value->action.type & CompBindingTypeKey) != 0;
                  beryl_value->value.as_binding.key_mod_mask = comp_value->action.key.modifiers;
                  beryl_value->value.as_binding.keysym = comp_value->action.key.keysym;
                  beryl_value->value.as_binding.enabled.value.button =
                        (comp_value->action.type & CompBindingTypeButton) != 0;
                  beryl_value->value.as_binding.button_mod_mask = comp_value->action.button.modifiers;
                  beryl_value->value.as_binding.button = comp_value->action.button.button;
                  beryl_value->value.as_binding.edge_mask = comp_value->action.edgeMask;
                  beryl_value->value.as_binding.on_bell = comp_value->action.bell;
                  break;
            case BERYL_SETTING_TYPE_LIST:
                  {
                        int i;
                        beryl_setting_list_clear(beryl_value->parent);
                        for (i=0;i<comp_value->list.nValue;i++)
                        {
                              BerylSettingValue * val = beryl_setting_list_append(beryl_value->parent);
                              comp_value_to_setting_value(&comp_value->list.value[i],val);
                        }
                  }
                  break;
            default:
                  break;
      }

}

static void setting_value_to_comp_value(BerylSettingValue * beryl_value, CompOptionValue * comp_value)
{
      BerylSettingType type;
      if (beryl_value->is_list_child)
            type=beryl_value->parent->info.for_list.list_of_type;
      else
            type=beryl_value->parent->type;
      switch(type)
      {
            case BERYL_SETTING_TYPE_INT:
                  comp_value->i=beryl_value->value.as_int;
                  break;
            case BERYL_SETTING_TYPE_FLOAT:
                  comp_value->f=beryl_value->value.as_float;
                  break;
            case BERYL_SETTING_TYPE_BOOL:
                  comp_value->b=beryl_value->value.as_bool;
                  break;
            case BERYL_SETTING_TYPE_COLOR:
                  {
                        int i;
                        for (i=0;i<4;i++)
                              comp_value->c[i]=beryl_value->value.as_color.array.array[i];
                  }
                  break;
            case BERYL_SETTING_TYPE_STRING:
                  //if (comp_value->s)
                  //    free (comp_value->s);
                  comp_value->s=strdup(beryl_value->value.as_string);
                  break;
            case BERYL_SETTING_TYPE_BINDING:
                  comp_value->action.type = CompBindingTypeNone;
                  if (beryl_value->value.as_binding.enabled.value.key)
                        comp_value->action.type |= CompBindingTypeKey;
                  comp_value->action.key.modifiers = beryl_value->value.as_binding.key_mod_mask;
                  comp_value->action.key.keysym = beryl_value->value.as_binding.keysym;
                  if (beryl_value->value.as_binding.enabled.value.button)
                        comp_value->action.type |= CompBindingTypeButton;
                  comp_value->action.button.modifiers = beryl_value->value.as_binding.button_mod_mask;
                  comp_value->action.button.button = beryl_value->value.as_binding.button;
                  comp_value->action.edgeMask=beryl_value->value.as_binding.edge_mask;
                  comp_value->action.bell=beryl_value->value.as_binding.on_bell;
                  break;
            case BERYL_SETTING_TYPE_LIST:
                  {
                        int len=g_slist_length(beryl_value->value.as_list);
                        comp_value->list.nValue=len;
                        if (len)
                        {
                              comp_value->list.value=malloc(sizeof(CompOptionValue)*len);
                              memset(comp_value->list.value,0,
                                          sizeof(CompOptionValue)*len);
                              GSList * i;
                              int j=0;
                              for (i=beryl_value->value.as_list;i;i=i->next)
                              {
                                    setting_value_to_comp_value(i->data,&comp_value->list.value[j]);
                                    j++;
                              }
                        }
                  }
                  break;
            default:
                  break;
      }
}

typedef struct _FindSubGroup
{
      gchar * subGroup;
      gboolean found;
      BerylSettingsSubGroup * found_at;
} FindSubGroup;

static void find_subgroup(BerylSettingsSubGroup * subGroup, FindSubGroup * find)
{
      if (find->found) return;
      if (!strcmp(subGroup->name,find->subGroup))
      {
            find->found=TRUE;
            find->found_at=subGroup;
      }
}

static void subgroup_add(BerylSetting * setting, BerylSettingsGroup * group)
{
      FindSubGroup f;
      f.found=FALSE;
      f.subGroup=setting->subGroup;
      g_slist_foreach(group->subGroups,(GFunc)find_subgroup,&f);
      if (!f.found)
      {
            NEW(BerylSettingsSubGroup,g);
            group->subGroups=g_slist_append(group->subGroups,g);
            g->name=g_strdup(setting->subGroup);
            f.found_at=g;
      }
      f.found_at->settings=g_slist_append(f.found_at->settings,setting);
}

typedef struct _FindGroup
{
      gchar * group;
      gboolean found;
      BerylSettingsGroup * found_at;
} FindGroup;

static void find_group(BerylSettingsGroup * group, FindGroup * find)
{
      if (find->found) return;
      if (!strcmp(group->name,find->group))
      {
            find->found=TRUE;
            find->found_at=group;
      }
}

static void group_add(BerylSetting * setting, BerylSettingsPlugin * plugin)
{
      FindGroup f;
      f.found=FALSE;
      f.group=setting->group;
      g_slist_foreach(plugin->groups,(GFunc)find_group,&f);
      if (!f.found)
      {
            NEW(BerylSettingsGroup,g);
            plugin->groups=g_slist_append(plugin->groups,g);
            g->name=g_strdup(setting->group);
            f.found_at=g;
      }
      subgroup_add(setting,f.found_at);
}

static void collate_groups(BerylSettingsPlugin * plugin)
{
      g_slist_foreach(plugin->settings,(GFunc)group_add,plugin);
}

static void category_add(BerylSettingsPlugin * plugin, BerylSettingsContext * context)
{
      BerylSettingsPluginCategory * pc = beryl_settings_plugin_get_category(plugin);
      pc->plugins=g_slist_append(pc->plugins,plugin);
}


static void collate_categories(BerylSettingsContext * context)
{
      g_slist_foreach(context->plugins,(GFunc)category_add,context);
}

static void load_plugin(BerylSettingsContext * context, gchar * filename)
{
      void * dlhand;
      gchar * err;
      PluginGetInfoProc getInfo;
      CompPluginVTable * vt;
      dlhand=dlopen(filename,RTLD_LAZY);
      if (!dlhand)
      {
            err=dlerror();
            if (err)
                  fprintf(stderr, _("libberylsettings: dlopen: %s\n"),err);
            return;
      }
      dlerror();
      getInfo = (PluginGetInfoProc) dlsym (dlhand, "getCompPluginInfo");
      if ((err=dlerror()))
      {
            fprintf (stderr, _("libberylsettings: dlsym: %s\n"), err);
            dlclose(dlhand);
            return;
      }
      vt=getInfo();
      if (vt->version != BERYL_VERSION ||
                  vt->struct_plugin_size != sizeof (CompPlugin) ||
                  vt->struct_display_size != sizeof (CompDisplay) ||
                  vt->struct_screen_size != sizeof (CompScreen) ||
                  vt->struct_window_size != sizeof (CompWindow) ||
                  vt->struct_texture_size != sizeof (CompTexture) ||
                  vt->struct_icon_size != sizeof (CompIcon))
      {
            fprintf (stderr, _("libberylsettings: Couldn't get vtable from '%s' plugin\n"), filename);
            dlclose (dlhand);
            return;
      }
      //make sure a plugin by the same name isn't already loaded
      if (beryl_settings_context_find_plugin(context,vt->name))
      {
            dlclose(dlhand);
            return;
      }
      NEW(BerylSettingsPlugin,plugin);
      plugin->context=context;
      plugin->name=g_strdup(vt->name);
      plugin->gettext_domain=g_strdup(vt->gettext_domain);
      plugin->short_desc=g_strdup(dgettext(plugin->gettext_domain,vt->shortDesc));
      plugin->long_desc=g_strdup(dgettext(plugin->gettext_domain,vt->longDesc));
      plugin->category=g_strdup(vt->category);
      plugin->filename=g_strdup(filename);
      int n;
      for (n=0;n<vt->nDeps;n++)
      {
            switch(vt->deps[n].rule)
            {
                  case CompPluginRuleBefore:
                        plugin->load_before=g_slist_append(
                                    plugin->load_before,g_strdup(vt->deps[n].name));
                        break;
                  case CompPluginRuleAfter:
                        plugin->load_after=g_slist_append(
                                    plugin->load_after,g_strdup(vt->deps[n].name));
                        break;
                  case CompPluginRuleRequire:
                        plugin->requires=g_slist_append(
                                    plugin->requires,g_strdup(vt->deps[n].name));
                        break;
                  default:
                        break;
            }
      }
      for (n=0;n<vt->nFeatures;n++)
      {
            plugin->provides=g_slist_append(plugin->provides,
                        g_strdup(vt->features[n].name));
      }
      if (vt->getDisplayOptions)
      {
            int n;
            CompOption * o;
            o = vt->getDisplayOptions(NULL,&n);
            for (;n;n--)
            {
                  init_option(plugin,o,FALSE);
                  o++;
            }
      }
      if (vt->getScreenOptions)
      {
            int n;
            CompOption * o;
            o = vt->getScreenOptions(NULL,&n);
            for (;n;n--)
            {
                  init_option(plugin,o,TRUE);
                  o++;
            }
      }
      if (vt->nGroupDescs)
      {
            int n;
            for (n=0;n<vt->nGroupDescs;n++)
            {
                  NEW(BerylSettingsGroup,g);
                  plugin->groups=g_slist_append(plugin->groups,g);
                  g->name=g_strdup(dgettext(plugin->gettext_domain,vt->groupDescs[n].name));
                  g->desc=g_strdup(dgettext(plugin->gettext_domain,vt->groupDescs[n].desc));
                  if (vt->groupDescs[n].nSubGroupDescs)
                  {
                        int j;
                        for (j=0;j<vt->groupDescs[n].nSubGroupDescs;j++)
                        {
                              NEW(BerylSettingsSubGroup,s);
                              g->subGroups=g_slist_append(g->subGroups,s);
                              s->name=g_strdup(dgettext(plugin->gettext_domain,
                                                vt->groupDescs[n].subGroupDescs[j].name));
                              s->desc=g_strdup(dgettext(plugin->gettext_domain,
                                                vt->groupDescs[n].subGroupDescs[j].desc));
                        }
                  }
            }
      }
      if (!beryl_settings_plugin_find_setting(plugin,"____plugin_enabled",FALSE))
      {
            NEW(BerylSetting,setting);
            setting->parent=plugin;
            setting->is_screen=FALSE;
            setting->is_default=TRUE;
            setting->name=g_strdup("____plugin_enabled");
            setting->short_desc=g_strdup("enabled");
            setting->long_desc=g_strdup("enabled");
            setting->group=g_strdup("");
            setting->subGroup=g_strdup("");
            setting->type=BERYL_SETTING_TYPE_BOOL;
            setting->advanced=TRUE;
            setting->default_value.parent=setting;
            setting->default_value.value.as_bool=vt->defaultEnabled;
            copy_from_default(setting);
            plugin->settings=g_slist_append(plugin->settings,setting);
      }
      else
      {
            g_error("Couldn't load plugin %s because it has a setting defined named ____plugin_enabled",plugin->name);
      }
      dlclose(dlhand);
      collate_groups(plugin);
      context->plugins=g_slist_append(context->plugins,plugin);
}

static void load_plugins(BerylSettingsContext * context, gchar * path)
      /* iterates through $path and adds any plugins found to the context
         $context        the context to add to
         $path           the path to search for plugins (any .so file) */
{
      GDir * d;
      const gchar * n;
      d=g_dir_open(path,0,NULL);
      if (!d)
            return; // no such path
      while((n=g_dir_read_name(d)))
      {
            if (g_str_has_suffix(n,".so") && g_str_has_prefix(n,"lib"))
            {
                  gchar * p;
                  p=g_strconcat(path,"/",n,NULL);
                  //actually load the plugin
                  load_plugin(context,p);
                  g_free(p);
            }
      }
      g_dir_close(d);
}

static void init_core_settings (BerylSettingsContext * context)
{
      NEW(BerylSettingsPlugin,plugin);
      plugin->category=g_strdup("");
      plugin->context=context;
      int n;
      CompOption * o;
      display = malloc(sizeof(CompDisplay));
      compDisplayInitOptions(display,NULL,0);
      plugin->gettext_domain=g_strdup("beryl-core");
      o=compGetDisplayOptions(NULL,&n);
      for (;n;n--)
      {
            init_option(plugin,o,FALSE);
            o++;
      }
      o=compGetOptions(&n);
      for (;n;n--)
      {
            init_option(plugin,o,TRUE);
            o++;
      }
      if (nCoreGroupDescs)
      {
            int n;
            for (n=0;n<nCoreGroupDescs;n++)
            {
                  NEW(BerylSettingsGroup,g);
                  plugin->groups=g_slist_append(plugin->groups,g);
                  g->name=g_strdup(dgettext(plugin->gettext_domain,coreGroupDescs[n].name));
                  g->desc=g_strdup(dgettext(plugin->gettext_domain,coreGroupDescs[n].desc));
                  if (coreGroupDescs[n].nSubGroupDescs)
                  {
                        int j;
                        for (j=0;j<coreGroupDescs[n].nSubGroupDescs;j++)
                        {
                              NEW(BerylSettingsSubGroup,s);
                              g->subGroups=g_slist_append(g->subGroups,s);
                              s->name=g_strdup(dgettext(plugin->gettext_domain,
                                                coreGroupDescs[n].subGroupDescs[j].name));
                              s->desc=g_strdup(dgettext(plugin->gettext_domain,
                                                coreGroupDescs[n].subGroupDescs[j].desc));
                        }
                  }
            }
      }
      collate_groups(plugin);
      context->plugins=g_slist_append(context->plugins,plugin);
}

static void free_value(BerylSettingValue * value)
{
      BerylSettingType type;
      if (value->is_list_child)
            type=value->parent->info.for_list.list_of_type;
      else
            type=value->parent->type;
      switch (type)
      {
            case BERYL_SETTING_TYPE_LIST:
                  g_slist_foreach(value->value.as_list,
                              (GFunc)free_value,NULL);
                  if (value->value.as_list)
                        g_slist_free(value->value.as_list);
                  break;
            case BERYL_SETTING_TYPE_STRING:
                  if (value->value.as_string)
                        g_free(value->value.as_string);
            default:
                  break;
      }
      if (value->is_list_child)
            free(value);
}

static void free_string_info(BerylSettingInfo * info)
{
      g_slist_foreach(info->for_string.allowed_values,
                  (GFunc)g_free,NULL);
      g_slist_foreach(info->for_string.raw_values,
                  (GFunc)g_free,NULL);
      if (info->for_string.allowed_values)
            g_slist_free(info->for_string.allowed_values);
      if (info->for_string.raw_values)
            g_slist_free(info->for_string.raw_values);
}

static void free_setting(BerylSetting * setting)
{
      if (setting->name) g_free(setting->name);
      if (setting->short_desc) g_free(setting->short_desc);
      if (setting->long_desc) g_free(setting->long_desc);
      if (setting->group) g_free(setting->group);
      if (setting->subGroup) g_free(setting->subGroup);
      if (setting->displayHints) g_free(setting->displayHints);
      free_value(&setting->default_value);
      free_value(&setting->value);
      if (setting->type == BERYL_SETTING_TYPE_STRING)
            free_string_info(&setting->info);
      if (setting->type == BERYL_SETTING_TYPE_LIST &&
                  setting->info.for_list.list_of_type == BERYL_SETTING_TYPE_STRING)
            free_string_info(setting->info.for_list.list_of_info);
      if (setting->type == BERYL_SETTING_TYPE_LIST)
            free(setting->info.for_list.list_of_info);
      free(setting);
}

static void free_subgroup(BerylSettingsSubGroup * subGroup)
{
      g_free(subGroup->name);
      if (subGroup->settings) g_slist_free(subGroup->settings);
}

static void free_group(BerylSettingsGroup * group)
{
      g_slist_foreach(group->subGroups,(GFunc)free_subgroup,NULL);
      if (group->subGroups) g_slist_free(group->subGroups);
      g_free(group->name);
}

static void free_plugin(BerylSettingsPlugin * plugin)
{
      if (plugin->category) g_free(plugin->category);
      if (plugin->name) g_free(plugin->name);
      if (plugin->short_desc) g_free(plugin->short_desc);
      if (plugin->long_desc) g_free(plugin->long_desc);
      if (plugin->gettext_domain) g_free(plugin->gettext_domain);
      if (plugin->filename) g_free(plugin->filename);
      g_slist_foreach(plugin->load_after,(GFunc)g_free,NULL);
      g_slist_foreach(plugin->load_before,(GFunc)g_free,NULL);
      g_slist_foreach(plugin->provides,(GFunc)g_free,NULL);
      g_slist_foreach(plugin->requires,(GFunc)g_free,NULL);
      g_slist_foreach(plugin->settings,(GFunc)free_setting,NULL);
      g_slist_foreach(plugin->groups,(GFunc)free_group,NULL);
      if (plugin->groups) g_slist_free(plugin->groups);
      if (plugin->load_after) g_slist_free(plugin->load_after);
      if (plugin->load_before) g_slist_free(plugin->load_before);
      if (plugin->provides) g_slist_free(plugin->provides);
      if (plugin->requires) g_slist_free(plugin->requires);
      if (plugin->settings) g_slist_free(plugin->settings);
      free(plugin);
}

typedef struct _BerylSettingsFindPlugin
{
      gchar * search_for;
      BerylSettingsPlugin * found;
} BerylSettingsFindPlugin;

static void find_plugin(BerylSettingsPlugin * plugin, BerylSettingsFindPlugin * find)
{
      if (find->found)
            return;
      if (find->search_for==NULL && plugin->name==NULL)
      {
            find->found=plugin;
            return;
      }
      if (find->search_for && plugin->name && strcmp(find->search_for,plugin->name)==0)
            find->found=plugin;
}

typedef struct _BerylSettingsFindSetting
{
      gchar * search_for;
      gboolean is_screen;
      BerylSetting * found;
} BerylSettingsFindSetting;

static void find_setting(BerylSetting * setting, BerylSettingsFindSetting * find)
{
      if (find->found)
            return;
      if (find->search_for &&
                  setting->name &&
                  find->is_screen==setting->is_screen &&
                  strcmp(find->search_for,setting->name)==0)
            find->found=setting;
}
static gboolean beryl_settings_compare_value(BerylSettingValue * v1, BerylSettingValue * v2)
{
      BerylSettingType t;
      if (v1->is_list_child)
            t=v1->parent->info.for_list.list_of_type;
      else
            t=v1->parent->type;

      switch(t)
      {
            case BERYL_SETTING_TYPE_LIST:
                  {
                        if (g_slist_length(v1->value.as_list)!=g_slist_length(v2->value.as_list))
                              return FALSE;
                        GSList * l, * m;
                        l=v1->value.as_list;
                        m=v2->value.as_list;
                        for (;l;l=l->next)
                        {
                              if (!beryl_settings_compare_value(l->data,m->data))
                                    return FALSE;
                              m=m->next;
                        }
                        return TRUE;
                  }
                  break;
            case BERYL_SETTING_TYPE_BOOL:
                  return (v1->value.as_bool==v2->value.as_bool);
            case BERYL_SETTING_TYPE_INT:
                  return (v1->value.as_int==v2->value.as_int);
            case BERYL_SETTING_TYPE_FLOAT:
                  return (v1->value.as_float==v2->value.as_float);
            case BERYL_SETTING_TYPE_STRING:
                  if (v1->value.as_string==NULL && v2->value.as_string==NULL)
                        return TRUE;
                  if (v1->value.as_string==NULL || v2->value.as_string==NULL)
                        return FALSE;
                  return (strcmp(v1->value.as_string,v2->value.as_string)==0);
            case BERYL_SETTING_TYPE_COLOR:
                  return (memcmp(&v1->value.as_color,&v2->value.as_color,sizeof(BerylSettingColorValue))==0);
            case BERYL_SETTING_TYPE_BINDING:
                  return (memcmp(&v1->value.as_binding,&v2->value.as_binding,sizeof(BerylSettingBindingValue))==0);
            default:
                  break;
      }
      return FALSE;
}
static void read_setting(BerylSetting * setting, BerylSettingsContext * c)
{
      BerylSettingValue v;
      v.parent=setting;
      v.is_list_child=FALSE;
      copy_value(&v,beryl_setting_get_primary_value(setting));
      beryl_setting_reset_to_default(setting);
      if (c->read_setting)
            c->read_setting(c,setting);
      if (!beryl_settings_compare_value(beryl_setting_get_primary_value(setting),&v))
      {
            if (!strcmp(beryl_setting_get_name(setting),"____plugin_enabled"))
                  c->plugins_changed=TRUE;
            else
                  c->changed_settings=g_slist_append(c->changed_settings,setting);
      }
      free_value(&v);
}
static void write_setting(BerylSetting * setting, BerylSettingsContext * c)
{
      if (c->write_setting)
            c->write_setting(c,setting);
}
static void read_settings_for_plugin(BerylSettingsPlugin * plugin,
            BerylSettingsContext * c)
{
      g_slist_foreach(plugin->settings,(GFunc)read_setting,c);
}

static void write_settings_for_plugin(BerylSettingsPlugin * plugin,
            BerylSettingsContext * c)
{
      g_slist_foreach(plugin->settings,(GFunc)write_setting,c);
}

typedef struct _BerylFindListSettingIndex
{
      int index;
      gboolean found;
      BerylSettingValue * value;
} BerylFindListSettingIndex;

static void find_index_of(BerylSettingValue * value, BerylFindListSettingIndex * find)
{
      if (find->found)
            return;
      if (find->value==value)
            find->found=TRUE;
      else
            find->index++;
}

static gboolean check_s_type(BerylSetting * setting, BerylSettingType type)
{
      if (setting->type==BERYL_SETTING_TYPE_LIST)
            return setting->info.for_list.list_of_type==type;
      else
            return setting->type==type;
}

static BerylSettingInfo * get_s_info(BerylSetting * setting)
{
      if (setting->type==BERYL_SETTING_TYPE_LIST)
            return setting->info.for_list.list_of_info;
      else
            return &setting->info;
}

static gboolean check_type(BerylSettingValue * value, BerylSettingType type)
{
      if (value->is_list_child)
            return value->parent->info.for_list.list_of_type==type;
      else
            return value->parent->type==type;
}

static BerylSettingInfo * get_info(BerylSettingValue * value)
{
      if (value->is_list_child)
            return value->parent->info.for_list.list_of_info;
      else
            return &value->parent->info;
}

static void init_general_options(BerylSettingsContext * context)
{
      GKeyFile * f;
      gchar * s;
      s = g_strconcat(g_get_home_dir(),"/.beryl/libberylsettings.ini",NULL);
      f = g_key_file_new();
      g_key_file_load_from_file(f,s,0,NULL);
      g_free(s);
      GError *e = NULL;
      context->de_integration =
                  g_key_file_get_boolean(f,"general","integration",&e);
      if (e)
            context->de_integration = TRUE;

      s=g_key_file_get_string(f,"general","backend",NULL);
      if (!s)
            beryl_settings_context_set_backend(context,"ini");
      else
      {
            if (!beryl_settings_context_set_backend(context,s))
                  beryl_settings_context_set_backend(context,"ini");
            g_free(s);
      }
      s=g_key_file_get_string(f,"general","profile",NULL);
      beryl_settings_context_set_profile(context,s);
      if (s)
            g_free(s);
      g_key_file_free(f);
}

static void save_general_option(BerylSettingsContext * context, generalOption opt)
{
      GKeyFile * f;
      gchar * s;
      s = g_strconcat(g_get_home_dir(),"/.beryl/",NULL);
      g_mkdir_with_parents(s,0755);
      g_free(s);
      s = g_strconcat(g_get_home_dir(),"/.beryl/libberylsettings.ini",NULL);
      f = g_key_file_new();
      g_key_file_load_from_file(f,s,0,NULL);
      switch(opt)
      {
            case OPT_BACKEND:
                  g_key_file_set_string(f,"general","backend",context->backend);
                  break;
            case OPT_PROFILE:
                  if (!context->profile)
                        g_key_file_remove_key(f,"general","profile",NULL);
                  else
                        g_key_file_set_string(f,"general","profile",context->profile);
                  break;
            case OPT_INTEGRATION:
                        g_key_file_set_boolean(f,"general", "integration",
                                                         context->de_integration);
                        printf("Set Integration %d\n",context->de_integration);
                  break;
      }
      gchar * d;
      d=g_key_file_to_data(f,NULL,NULL);
      g_file_set_contents(s,d,-1,NULL);
      g_free(d);
      g_free(s);
      g_key_file_free(f);
}

static void add_backend(gchar * basename, gchar * soname)
{
      gchar * bn;
      void * d = dlopen(soname,RTLD_LAZY);
      if (!d) return;
      bn = malloc(strlen(basename)-5);
      bn[strlen(basename)-6]='\0';
      strncpy(bn,basename+3,strlen(basename)-6);
      GSList * n = Backends;
      for (;n;n=n->next)
      {
            if (!strcmp(bn,((BerylSettingsBackend *)n->data)->name))
            {
                  dlclose(d);
                  free(bn);
                  return;
            }
      }
      NEW(BerylSettingsBackend,b);
      BSBDescFunc de;
      BSBIntegFunc in;
      de = dlsym(d,"get_short_desc");
      in = dlsym(d,"get_supports_integration");
      b->name = g_strdup(bn);
      free(bn);
      if (de)
            b->short_desc=g_strdup(de());
      else
            b->short_desc=g_strdup(b->name);
      if (in)
            b->supports_integration=in();
      else
            b->supports_integration=False;
      Backends = g_slist_append(Backends,b);
}

static void fill_backends_dir(gchar * path)
{
      GDir * d;
      gchar * n;
      d = g_dir_open(path,0,NULL);
      if (d)
      {
            while((n=(gchar *)g_dir_read_name(d)))
            {
                  if (g_str_has_suffix(n,".so") && g_str_has_prefix(n,"lib"))
                  {
                        gchar * p;
                        p=g_strconcat(path,"/",n,NULL);
                        add_backend(n,p);
                        g_free(p);
                  }
            }
            g_dir_close(d);
      }
}

static void fill_backends_list(void)
{
      gchar * path = g_strconcat(g_get_home_dir(),"/.beryl/backends/",NULL);
      fill_backends_dir(path);
      g_free(path);
      fill_backends_dir(PLUGINDIR "/backends/");
}

static void * open_backend(gchar * backend)
{
      // prefer local backend...
      void * backend_dlhand;
      gchar * dlname=g_strconcat(g_get_home_dir(),"/.beryl/backends/lib",
                  backend,".so",NULL);
      gchar * eret;
      gchar * eret2=NULL;

      eret = dlerror();
      g_free(eret);
      backend_dlhand=dlopen(dlname,RTLD_NOW);
      eret=dlerror();
      if (eret || !backend_dlhand)
      {
            eret2=eret;
            g_free(dlname);
            dlname=g_strconcat(PLUGINDIR,"/backends/lib",backend,".so",NULL);
            backend_dlhand=dlopen(dlname,RTLD_NOW);
            eret=dlerror();
      }
      if (eret || !backend_dlhand)
      {
            if (eret2)
                  g_message(eret2);
            g_message(eret);
            g_free(dlname);
            return NULL;
      }
      if (dlname)
      {
            g_free(dlname);
      }

      g_free(eret);

      return backend_dlhand;

}

typedef struct _ImportInfo
{
      gboolean overwrite;
      BerylSettingsContext * context;
      BerylSettingsContextReadSettingFunc readfunc;
} ImportInfo;

typedef struct _ExportInfo
{
      BerylSettingsContext * context;
      BerylSettingsContextWriteSettingFunc writefunc;
} ExportInfo;


static void import_for_setting(BerylSetting * s, ImportInfo * i)
{
      if (s->is_default || i->overwrite)
            i->readfunc(i->context,s);
}

static void import_for_plugin(BerylSettingsPlugin * p, ImportInfo * i)
{
      g_slist_foreach(p->settings,(GFunc)import_for_setting,i);
}

static void export_for_setting(BerylSetting * s, ExportInfo * i)
{
      if (!s->is_default)
            i->writefunc(i->context,s);
}

static void export_for_plugin(BerylSettingsPlugin * p, ExportInfo * i)
{
      g_slist_foreach(p->settings,(GFunc)export_for_setting,i);
}

typedef struct _FindConflict
{
      GSList * retlist;
      BerylSettingConflictType type; // type currently seeking
      BerylSetting * seeking_setting;
} FindConflict;

static void plugin_find_conflicts(BerylSettingsPlugin * p, FindConflict * f);

static void add_conflict(BerylSetting * s, FindConflict * f)
{
      GSList * l;
      for (l=f->retlist;l;l=l->next)
      {
            BerylSettingConflict * c = l->data;
            if (c->type==f->type)
            {
                  GSList * m;
                  for(m=c->settings;m;m=m->next)
                  {
                        if (m->data==f->seeking_setting)
                              break;
                  }
                  if (m)
                        break;
            }
      }
      if (l)
      {
            BerylSettingConflict * c = l->data;
            c->settings=g_slist_append(c->settings,s);
      }
      else
      {
            NEW(BerylSettingConflict,c);
            c->type=f->type;
            c->settings=g_slist_append(c->settings,f->seeking_setting);
            c->settings=g_slist_append(c->settings,s);
            f->retlist=g_slist_append(f->retlist,c);
      }
}

static void setting_find_conflicts(BerylSetting * s, FindConflict * f)
{
      if (s->type != BERYL_SETTING_TYPE_BINDING)
            return;
      switch(f->type)
      {
            case BERYL_SETTING_CONFLICT_TYPE_KEY:
                  if (!s->info.for_bind.key)
                        return;
                  break;
            case BERYL_SETTING_CONFLICT_TYPE_BUTTON:
                  if (!s->info.for_bind.button)
                        return;
                  break;
            case BERYL_SETTING_CONFLICT_TYPE_EDGE:
                  if (!s->info.for_bind.edge)
                        return;
                  break;
            default:
                  break;
      }
      if (s==f->seeking_setting)
            return;
      if (f->seeking_setting)
      {
            //TODO support list-of-bindings
            switch(f->type)
            {
                  case BERYL_SETTING_CONFLICT_TYPE_KEY:
                        if (s->value.value.as_binding.enabled.value.key &&
                            f->seeking_setting->value.value.as_binding.enabled.value.key)
                              if (s->value.value.as_binding.keysym==
                                          f->seeking_setting->value.value.as_binding.keysym &&
                                          s->value.value.as_binding.key_mod_mask==
                                          f->seeking_setting->value.value.as_binding.key_mod_mask)
                                    add_conflict(s,f);
                        break;
                  case BERYL_SETTING_CONFLICT_TYPE_BUTTON:
                        if (s->value.value.as_binding.enabled.value.button &&
                              f->seeking_setting->value.value.as_binding.enabled.value.button)
                              if (s->value.value.as_binding.button==
                                          f->seeking_setting->value.value.as_binding.button &&
                                          s->value.value.as_binding.button_mod_mask==
                                          f->seeking_setting->value.value.as_binding.button_mod_mask)
                                    add_conflict(s,f);
                        break;
                  case BERYL_SETTING_CONFLICT_TYPE_EDGE:
                        if (s->value.value.as_binding.edge_mask &
                                    f->seeking_setting->value.value.as_binding.edge_mask)
                              add_conflict(s,f);
                        break;
                  default:
                        g_warning("Invalid CONFLICT TYPE");
            }
      }
      else
      {
            GSList * l;
            for(l=f->retlist;l;l=l->next)
            {
                  BerylSettingConflict * c = l->data;
                  if (c->type==f->type)
                  {
                        GSList * m;
                        for(m=c->settings;m;m=m->next)
                        {
                              if (m->data==s)
                                    return;
                        }
                  }
            }
            f->seeking_setting=s;
            g_slist_foreach(s->parent->context->plugins,
                        (GFunc)plugin_find_conflicts,f);
            f->seeking_setting=NULL;
      }
}

static void plugin_find_conflicts(BerylSettingsPlugin * p, FindConflict * f)
{
      g_slist_foreach(p->settings,(GFunc)setting_find_conflicts,f);
}

//EXPORTED FUNCTIONS
BerylSettingsContext * beryl_settings_context_new(void)
{
      gchar * homeplugins=g_strconcat(g_get_home_dir(),"/.beryl/plugins",NULL);
      NEW(BerylSettingsContext,context);
      context->categories=malloc(sizeof(PluginCategories));
      memcpy(context->categories,&PluginCategories,sizeof(PluginCategories));
      init_core_settings(context);
      load_plugins(context,homeplugins);
      load_plugins(context,PLUGINDIR);    // load after, because that way name conflicts
      // will lead to the home version being loaded
      g_free(homeplugins);
      collate_categories(context);
      init_general_options(context);
      return context;
}

gboolean beryl_settings_context_set_backend(BerylSettingsContext * context,
            gchar * backend)
{
      if (context->backend)
      {
            dlclose(context->backend_dlhand);
            context->backend_dlhand=0;
            context->read_setting=0;
            context->write_setting=0;
            context->read_init=0;
            context->read_done=0;
            context->write_init=0;
            context->write_done=0;
            context->backend_init=0;
            context->backend_fini=0;
            context->delete_profile=0;
            context->get_existing_profiles=0;
            context->get_setting_is_integrated=0;
            context->get_setting_is_read_only=0;
            context->setting_changed = 0;
            g_free(context->backend);
            context->backend=0;
      }

      context->backend_dlhand=open_backend(backend);
      if (!context->backend_dlhand)
            context->backend_dlhand=open_backend("ini"); // failover, situation would be pathological if this fails

      context->backend=g_strdup(backend);
#define LOAD_ITEM(n) \
      context->n =dlsym(context->backend_dlhand,#n);\
      if(!context->n  )\
      g_warning(#n " not found in backend %s",backend);
      LOAD_ITEM(read_setting);
      LOAD_ITEM(write_setting);
      LOAD_ITEM(read_init);
      LOAD_ITEM(read_done);
      LOAD_ITEM(write_init);
      LOAD_ITEM(write_done);
      LOAD_ITEM(get_setting_is_integrated);
      LOAD_ITEM(get_setting_is_read_only);
      LOAD_ITEM(get_existing_profiles);
      LOAD_ITEM(backend_init);
      LOAD_ITEM(backend_fini);
      LOAD_ITEM(delete_profile);

      save_general_option(context,OPT_BACKEND);

      if (context->backend_init)
            context->backend_init(context);
      return TRUE;
}

void beryl_settings_context_destroy(BerylSettingsContext * context)
{
      int i;
      if (context->backend_fini)
            context->backend_fini(context);
      g_slist_foreach(context->plugins,(GFunc)free_plugin,NULL);
      if (context->profile) g_free(context->profile);
      if (context->plugins) g_slist_free(context->plugins);
      if (context->backend)
      {
            dlclose(context->backend_dlhand);
            g_free(context->backend);
      }
      for (i=0;i<nPluginCategories;i++)
      {
            if (context->categories[i].plugins)
                  g_slist_free(context->categories[i].plugins);
      }
      free(context->categories);
      free(context);
}

GSList * beryl_settings_plugin_get_groups(BerylSettingsPlugin * plugin)
{
      return plugin->groups;
}

BerylSettingsGroup * beryl_settings_plugin_find_group(BerylSettingsPlugin * plugin, gchar * group)
{
      GSList * l = plugin->groups;
      while(l)
      {
            if (!strcmp(beryl_settings_group_get_name(l->data),group))
                  return l->data;
            l=l->next;
      }
      return NULL;
}

gchar * beryl_settings_group_get_name(BerylSettingsGroup * group)
{
      return group->name;
}

gchar * beryl_settings_group_get_desc(BerylSettingsGroup * group)
{
      return group->desc;
}

GSList * beryl_settings_group_get_subgroups(BerylSettingsGroup * group)
{
      return group->subGroups;
}

BerylSettingsSubGroup * beryl_settings_group_find_subgroup(BerylSettingsGroup * group, gchar * subgroup)
{
      GSList * l = group->subGroups;
      while(l)
      {
            if (!strcmp(beryl_settings_subgroup_get_name(l->data),subgroup))
                  return l->data;
            l=l->next;
      }
      return NULL;
}

gchar * beryl_settings_subgroup_get_name(BerylSettingsSubGroup * subGroup)
{
      return subGroup->name;
}

gchar * beryl_settings_subgroup_get_desc(BerylSettingsSubGroup * subGroup)
{
      return subGroup->desc;
}

GSList * beryl_settings_subgroup_get_settings(BerylSettingsSubGroup * subGroup)
{
      return subGroup->settings;
}

BerylSetting * beryl_settings_subgroup_find_setting(BerylSettingsSubGroup * subGroup, gchar * setting)
      //WARNING - doesn't care about is_screen
{
      GSList * l = subGroup->settings;
      while(l)
      {
            if (!strcmp(beryl_setting_get_name(l->data),setting))
                  return l->data;
            l=l->next;
      }
      return NULL;
}


gboolean beryl_setting_has_hint(BerylSetting * setting, gchar * hint)
{

            gboolean ret;
            gchar * hhint = g_strconcat(hint,";",NULL);
            ret=strstr(setting->displayHints,hhint)?TRUE:FALSE;
            g_free(hhint);
            return ret;

}

BerylSettingsPlugin * beryl_settings_context_find_plugin(BerylSettingsContext * context, gchar * name)
{
      BerylSettingsFindPlugin find;
      find.found=NULL;
      find.search_for=name;
      g_slist_foreach(context->plugins,(GFunc)find_plugin,&find);
      return find.found;
}

BerylSetting * beryl_settings_plugin_find_setting(BerylSettingsPlugin * plugin, gchar * name,
            gboolean is_screen)
{
      BerylSettingsFindSetting find;
      find.found=NULL;
      find.search_for=name;
      find.is_screen=is_screen;
      g_slist_foreach(plugin->settings,(GFunc)find_setting,&find);
      return find.found;
}

GSList * beryl_settings_context_get_settings_changed(BerylSettingsContext * c)
{
      return c->changed_settings;
}

gboolean beryl_settings_context_get_if_plugins_changed(BerylSettingsContext * c)
{
      return c->plugins_changed;
}

void beryl_settings_context_read(BerylSettingsContext * context)
{
      if (context->changed_settings)
            g_slist_free(context->changed_settings);
      context->changed_settings=NULL;
      context->plugins_changed=FALSE;
      if (context->read_init)
            if (!context->read_init(context)) return;
      g_slist_foreach(context->plugins,(GFunc)read_settings_for_plugin,context);
      if (context->read_done)
            context->read_done(context);
}

void beryl_settings_context_write(BerylSettingsContext * context)
{
      if (context->write_init)
            if (!context->write_init(context)) return;
      g_slist_foreach(context->plugins,(GFunc)write_settings_for_plugin,context);
      if (context->write_done)
            context->write_done(context);
}

#if 0 /* Incomplete */
void beryl_settings_context_comp_free_option(s_plugin, option)
{
      BerylSetting * setting;

      g_free(setting->name);
      g_free(setting->short_desc);
      g_free(setting->long_desc);
      free_value(setting->value);
}
#endif

gboolean beryl_settings_context_comp_get_option_value(BerylSettingsContext * context,
            gchar * plugin, gchar * name, gboolean is_screen, CompOptionValue * value)
{
      BerylSettingsPlugin * s_plugin;
      BerylSetting * setting;
      if (!(s_plugin=beryl_settings_context_find_plugin(context,plugin)))
      {
            return FALSE;
      }
      if (!(setting=beryl_settings_plugin_find_setting(s_plugin,name,is_screen)))
      {
            return FALSE;
      }
      setting_value_to_comp_value(&setting->value,value);
      return TRUE;
}

gboolean beryl_settings_context_comp_set_option_value(BerylSettingsContext * context,
            gchar * plugin, gchar * name, gboolean is_screen, CompOptionValue * value)
{
      BerylSettingsPlugin * s_plugin;
      BerylSetting * setting;
      if (!(s_plugin=beryl_settings_context_find_plugin(context,plugin)))
            return FALSE;
      if (!(setting=beryl_settings_plugin_find_setting(s_plugin,name,is_screen)))
            return FALSE;
      setting->is_default=FALSE;
      comp_value_to_setting_value(value,&setting->value);
      return TRUE;
}

gboolean beryl_settings_send_reload_signal(void)
{
      Atom wmAtom = 0;
      Display *dpy = XOpenDisplay(NULL);

      char buffer[128];

      sprintf(buffer, "WM_S%d", dpy ? DefaultScreen(dpy) : 0);

      if (dpy)
            wmAtom = XInternAtom(dpy,buffer,0);

      if (wmAtom) {
            printf("Sending reload event...\n");
            XEvent clientEvent;
            Status missed;
            Window w = XGetSelectionOwner(dpy,wmAtom);
            Atom ReloadIt = XInternAtom(dpy, BERYL_SETTINGS_RELOAD_ATOM, FALSE);
            clientEvent.xclient.type = ClientMessage;
            clientEvent.xclient.window = w;
            clientEvent.xclient.message_type = ReloadIt;
            clientEvent.xclient.format = 32;
            clientEvent.xclient.display = dpy;
            clientEvent.xclient.data.l[0]    = 0;
            clientEvent.xclient.data.l[1]    = 0;
            clientEvent.xclient.data.l[2]    = 0;
            clientEvent.xclient.data.l[3]    = 0;
            clientEvent.xclient.data.l[4]    = 0;
            missed = XSendEvent(dpy,w,
                        False,
                        NoEventMask,
                        &clientEvent);
            XSync (dpy, False);
            XCloseDisplay(dpy);
      } else {
            // The old way
            printf("Sending reload signal...\n");
            gchar * args[] =
            {"killall","-u",(gchar *)g_get_user_name(),"-SIGUSR1","-r","^beryl$|^beryl-xgl$",NULL};
            gchar * ret=NULL;
            if (!g_spawn_sync(NULL,args,NULL,G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH,
                              NULL,NULL,&ret,NULL,NULL,NULL) || !ret)
                  return FALSE;
      }
      return TRUE;
}

void beryl_setting_reset_to_default(BerylSetting * setting)
{
      //if (!setting->is_default)
      free_value(&setting->value);
      copy_from_default(setting);
      setting->is_default=TRUE;
}

void beryl_setting_list_clear(BerylSetting * setting)
{
      if (setting->type != BERYL_SETTING_TYPE_LIST)
            return;
      setting->is_default=FALSE;
      g_slist_foreach(setting->value.value.as_list,
                  (GFunc)free_value,NULL);
      if (setting->value.value.as_list)
            g_slist_free(setting->value.value.as_list);
      setting->value.value.as_list=NULL;
}

BerylSettingValue * beryl_setting_list_append(BerylSetting * setting)
{
      if (setting->type != BERYL_SETTING_TYPE_LIST)
            return NULL;
      setting->is_default=FALSE;
      NEW(BerylSettingValue,value);
      value->parent=setting;
      value->is_list_child=TRUE;
      setting->value.value.as_list=g_slist_append(setting->value.value.as_list,value);
      return value;
}

gint beryl_setting_list_length(BerylSetting * setting)
{
      if (setting->type != BERYL_SETTING_TYPE_LIST)
            return -1;
      return g_slist_length(setting->value.value.as_list);
}

gint beryl_setting_list_value_index(BerylSettingValue * value)
{
      if (!value->is_list_child)
            return -1;
      BerylFindListSettingIndex find;
      find.found=FALSE;
      find.index=0;
      find.value=value;
      g_slist_foreach(value->parent->value.value.as_list,(GFunc)find_index_of,&find);
      if (find.found)
            return find.index;
      else
            return -1;
}

void beryl_setting_list_value_swap_with(BerylSettingValue * value, guint n)
{
      if (!value->is_list_child)
            return;
      GSList * a = g_slist_nth(value->parent->value.value.as_list,n);
      GSList * b = g_slist_find(value->parent->value.value.as_list,value);
      if (!a || !b)
            return;
      value->parent->is_default=FALSE;
      b->data=a->data;
      a->data=value;
}

void beryl_setting_list_value_move_before(BerylSettingValue * value, guint n)
{
      if (!value->is_list_child)
            return;
      GSList * a = g_slist_nth(value->parent->value.value.as_list,n);
      if (a && a->data==value)
            return;
      value->parent->is_default=FALSE;
      if (!a)
      {
            value->parent->value.value.as_list=g_slist_append(g_slist_remove(
                              value->parent->value.value.as_list,value),value);
            return;
      }
      value->parent->value.value.as_list=g_slist_insert_before(
                  g_slist_remove(value->parent->value.value.as_list,value),a,value);
}

void beryl_setting_list_value_remove(BerylSettingValue * value)
{
      if (!value->is_list_child)
            return;
      value->parent->is_default=FALSE;
      value->parent->value.value.as_list=g_slist_remove(
                  value->parent->value.value.as_list,value);
      free_value(value);
}

BerylSettingValue * beryl_setting_get_primary_value(BerylSetting * setting)
{
      return &setting->value;
}

gboolean beryl_setting_value_get_int(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_INT))
            return FALSE;
      *data=value->value.as_int;
      return TRUE;
}

gboolean beryl_setting_value_get_float(BerylSettingValue * value, gdouble * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_FLOAT))
            return FALSE;
      *data=value->value.as_float;
      return TRUE;
}

gboolean beryl_setting_value_get_bool(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BOOL))
            return FALSE;
      *data=value->value.as_bool;
      return TRUE;
}

gboolean beryl_setting_value_get_string(BerylSettingValue * value, const gchar ** data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_STRING))
            return FALSE;
      BerylSettingInfo * info=get_info(value);
      if (info->for_string.raw_values)
      {

            GSList * reststring=info->for_string.raw_values;
            GSList * xlatstring=info->for_string.allowed_values;
            while(reststring)
            {
                  if (strcmp(value->value.as_string,reststring->data)==0)
                  {
                        *data=xlatstring->data;
                        return TRUE;
                  }
                  reststring=reststring->next;
                  xlatstring=xlatstring->next;
            }
      }
      else
      {
            *data=value->value.as_string;
            return TRUE;
      }
      return FALSE;
}

gboolean beryl_setting_value_get_keysym(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.keysym;
      return TRUE;
}

gboolean beryl_setting_value_get_keymods(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.key_mod_mask;
      return TRUE;
}

gboolean beryl_setting_value_get_button(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.button;
      return TRUE;
}

gboolean beryl_setting_value_get_buttonmods(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.button_mod_mask;
      return TRUE;
}

gboolean beryl_setting_value_get_edgemask(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.edge_mask;
      return TRUE;
}

gboolean beryl_setting_value_get_bell(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.on_bell;
      return TRUE;
}

gboolean beryl_setting_value_get_key_enabled(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.enabled.value.key;
      return TRUE;
}

gboolean beryl_setting_value_get_button_enabled(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=value->value.as_binding.enabled.value.button;
      return TRUE;
}

gboolean beryl_setting_value_get_color(BerylSettingValue * value, BerylSettingColorValue * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_COLOR))
            return FALSE;
      memcpy(data,&value->value.as_color,sizeof(BerylSettingColorValue));
      return TRUE;
}

gboolean beryl_setting_value_get_value_list(BerylSettingValue * value, GSList ** data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_LIST))
            return FALSE;
      *data=value->value.as_list;
      return TRUE;
}

gboolean beryl_setting_value_set_int(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_INT))
            return FALSE;
      BerylSettingInfo * info = get_info(value);
      if (*data<info->for_int.min || *data>info->for_int.max)
            return FALSE;
      value->parent->is_default=FALSE;
      value->value.as_int=*data;
      return TRUE;
}

gboolean beryl_setting_value_set_float(BerylSettingValue * value, gdouble * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_FLOAT))
            return FALSE;
      BerylSettingInfo * info = get_info(value);
      if (*data<info->for_float.min || *data>info->for_float.max)
            return FALSE;
      value->parent->is_default=FALSE;
      value->value.as_float=*data;
      return TRUE;
}

gboolean beryl_setting_value_set_bool(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BOOL))
            return FALSE;
      value->parent->is_default=FALSE;
      value->value.as_bool=*data;
      return TRUE;
}

gboolean beryl_setting_value_set_raw_string(BerylSettingValue * value, const gchar ** data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_STRING))
            return FALSE;
      BerylSettingInfo * info = get_info(value);
      if (info->for_string.raw_values)
      {
            GSList * reststring=info->for_string.raw_values;
            while(reststring)
            {
                  if (strcmp(*data,reststring->data)==0)
                  {
                        if (value->value.as_string)
                              g_free(value->value.as_string);
                        value->value.as_string=g_strdup(reststring->data);
                        value->parent->is_default=FALSE;
                        return TRUE;
                  }
                  reststring=reststring->next;
            }
            return FALSE;
      }
      if (value->value.as_string)
            g_free(value->value.as_string);
      value->value.as_string=g_strdup(*data);
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_string(BerylSettingValue * value, const gchar ** data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_STRING))
            return FALSE;
      BerylSettingInfo * info = get_info(value);
      if (info->for_string.raw_values)
      {
            GSList * reststring=info->for_string.raw_values;
            GSList * xlatstring=info->for_string.allowed_values;
            while(reststring)
            {
                  if (strcmp(*data,xlatstring->data)==0)
                  {
                        if (value->value.as_string)
                              g_free(value->value.as_string);
                        value->value.as_string=g_strdup(reststring->data);
                        value->parent->is_default=FALSE;
                        return TRUE;
                  }
                  reststring=reststring->next;
                  xlatstring=xlatstring->next;
            }
      }
      else
      {
            if (value->value.as_string)
                  g_free(value->value.as_string);
            value->value.as_string=g_strdup(*data);
            value->parent->is_default=FALSE;
            return TRUE;
      }
      return FALSE;
}

gboolean beryl_setting_value_set_keysym(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.key)
            return FALSE;
      value->value.as_binding.keysym=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_keymods(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.key)
            return FALSE;
      value->value.as_binding.key_mod_mask=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_button(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.button)
            return FALSE;
      value->value.as_binding.button=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_buttonmods(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.button)
            return FALSE;
      value->value.as_binding.button_mod_mask=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_edgemask(BerylSettingValue * value, gint * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.edge)
            return FALSE;
      value->value.as_binding.edge_mask=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_bell(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.bell)
            return FALSE;
      value->value.as_binding.on_bell=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_key_enabled(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.key)
            return FALSE;
      value->value.as_binding.enabled.value.key=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_button_enabled(BerylSettingValue * value, gboolean * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      if (!get_info(value)->for_bind.button)
            return FALSE;
      value->value.as_binding.enabled.value.button=*data;
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_value_set_color(BerylSettingValue * value, BerylSettingColorValue * data)
{
      if (!check_type(value,BERYL_SETTING_TYPE_COLOR))
            return FALSE;
      memcpy(&value->value.as_color,data,sizeof(BerylSettingColorValue));
      value->parent->is_default=FALSE;
      return TRUE;
}

gboolean beryl_setting_get_can_set_key(BerylSetting * setting, gboolean * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=get_s_info(setting)->for_bind.key;
      return TRUE;
}

gboolean beryl_setting_get_can_set_button(BerylSetting * setting, gboolean * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=get_s_info(setting)->for_bind.button;
      return TRUE;
}

gboolean beryl_setting_get_can_set_edgemask(BerylSetting * setting, gboolean * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=get_s_info(setting)->for_bind.edge;
      return TRUE;
}

gboolean beryl_setting_get_can_set_bell(BerylSetting * setting, gboolean * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_BINDING))
            return FALSE;
      *data=get_s_info(setting)->for_bind.bell;
      return TRUE;
}

gboolean beryl_setting_get_allowed_strings(BerylSetting * setting, GSList ** data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_STRING))
            return FALSE;
      *data=get_s_info(setting)->for_string.allowed_values;
      return TRUE;
}

gboolean beryl_setting_get_raw_allowed_strings(BerylSetting * setting, GSList ** data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_STRING))
            return FALSE;
      *data=get_s_info(setting)->for_string.raw_values;
      return TRUE;
}

gboolean beryl_setting_get_int_max(BerylSetting * setting, gint * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_INT))
            return FALSE;
      *data=get_s_info(setting)->for_int.max;
      return TRUE;
}

gboolean beryl_setting_get_int_min(BerylSetting * setting, gint * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_INT))
            return FALSE;
      *data=get_s_info(setting)->for_int.min;
      return TRUE;
}

gboolean beryl_setting_get_float_min(BerylSetting * setting, gdouble * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_FLOAT))
            return FALSE;
      *data=get_s_info(setting)->for_float.min;
      return TRUE;
}

gboolean beryl_setting_get_float_max(BerylSetting * setting, gdouble * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_FLOAT))
            return FALSE;
      *data=get_s_info(setting)->for_float.max;
      return TRUE;
}

gboolean beryl_setting_get_float_precision(BerylSetting * setting, gdouble * data)
{
      if (!check_s_type(setting,BERYL_SETTING_TYPE_FLOAT))
            return FALSE;
      *data=get_s_info(setting)->for_float.precision;
      return TRUE;
}

gboolean beryl_setting_get_list_type(BerylSetting * setting, BerylSettingType * data)
{
      if (setting->type != BERYL_SETTING_TYPE_LIST)
            return FALSE;
      *data=setting->info.for_list.list_of_type;
      return TRUE;
}

BerylSettingType beryl_setting_get_type(BerylSetting * setting)
{
      return setting->type;
}

const gchar * beryl_setting_get_short_desc(BerylSetting * setting)
{
      return setting->short_desc;
}

const gchar * beryl_setting_get_long_desc(BerylSetting * setting)
{
      return setting->long_desc;
}

const gchar * beryl_setting_get_group(BerylSetting * setting)
{
      return setting->group;
}

const gchar * beryl_setting_get_subgroup(BerylSetting * setting)
{
      return setting->subGroup;
}

const gchar * beryl_setting_get_name(BerylSetting * setting)
{
      return setting->name;
}

const gchar * beryl_settings_plugin_get_short_desc(BerylSettingsPlugin * plugin)
{
      return plugin->short_desc;
}

const gchar * beryl_settings_plugin_get_long_desc(BerylSettingsPlugin * plugin)
{
      return plugin->long_desc;
}

const gchar * beryl_settings_plugin_get_name(BerylSettingsPlugin * plugin)
{
      return plugin->name;
}

GSList * beryl_settings_context_get_plugins(BerylSettingsContext * context)
{
      return context->plugins;
}

GSList * beryl_settings_plugin_get_settings(BerylSettingsPlugin * plugin)
{
      return plugin->settings;
}

gpointer beryl_settings_context_get_private(BerylSettingsContext * context)
{
      return context->private_ptr;
}

void beryl_settings_context_set_private(BerylSettingsContext * context, gpointer private_ptr)
{
      context->private_ptr = private_ptr;
}

gpointer beryl_settings_plugin_get_private(BerylSettingsPlugin * plugin)
{
      return plugin->private_ptr;
}

void beryl_settings_plugin_set_private(BerylSettingsPlugin * plugin, gpointer private_ptr)
{
      plugin->private_ptr = private_ptr;
}

gpointer beryl_setting_get_private(BerylSetting * setting)
{
      return setting->private_ptr;
}

void beryl_setting_set_private(BerylSetting * setting, gpointer private_ptr)
{
      setting->private_ptr = private_ptr;
}

int beryl_settings_get_plugin_category_count(void)
{
      return nPluginCategories;
}

BerylSettingsPluginCategory * beryl_settings_context_get_nth_plugin_category(BerylSettingsContext * context, int i)
{
      return &(context->categories[i]);
}

BerylSettingsPluginCategory * beryl_settings_plugin_get_category(BerylSettingsPlugin * plugin)
{
      int i;
      for (i=0;i<nPluginCategories;i++)
      {
            if (!strcmp(plugin->context->categories[i].name,plugin->category))
                  break;
      }
      if (i>=nPluginCategories)
      {
            g_message("Unknown category %s",plugin->category);
            i=(nPluginCategories-1);
      }
      return &plugin->context->categories[i];
}

const gchar * beryl_settings_plugin_category_get_name(BerylSettingsPluginCategory * category)
{
      return category->name;
}

const gchar * beryl_settings_plugin_category_get_short_desc(BerylSettingsPluginCategory * category)
{
      return dgettext("beryl-core",category->short_desc);
}

const gchar * beryl_settings_plugin_category_get_long_desc(BerylSettingsPluginCategory * category)
{
      return dgettext("beryl-core",category->long_desc);
}

GSList * beryl_settings_plugin_category_get_plugins(BerylSettingsPluginCategory * category)
{
      return category->plugins;
}

void beryl_settings_context_set_profile(BerylSettingsContext * context, gchar * profile)
{
      if (context->profile)
            g_free(context->profile);
      if (profile)
            context->profile=g_strdup(profile);
      else
            context->profile=NULL;
      save_general_option(context,OPT_PROFILE);
}

gchar * beryl_settings_context_get_profile(BerylSettingsContext * context)
{
      return context->profile;
}

void beryl_settings_context_set_de_integration_enabled(BerylSettingsContext * context, gboolean enable_integration)
{
      context->de_integration=enable_integration;
      save_general_option(context,OPT_INTEGRATION);
}

gboolean beryl_settings_context_get_de_integration_enabled(BerylSettingsContext * context)
{
      return context->de_integration;
}

gchar * beryl_settings_context_get_backend(BerylSettingsContext * context)
{
      return context->backend;
}


/*    gboolean                      de_integrated;    // this setting is integrated into the
// desktop environment setting system
gboolean                      read_only;        // the backend ignores changes to this setting*/
gboolean beryl_settings_context_get_setting_is_de_integrated(BerylSettingsContext * context, BerylSetting * setting)
{
      if (context->get_setting_is_integrated)
            return context->get_setting_is_integrated(setting);
      else
            return FALSE;
}

gboolean beryl_settings_context_get_setting_is_read_only(BerylSettingsContext * context, BerylSetting * setting)
{
      if (context->get_setting_is_read_only)
            return context->get_setting_is_read_only(setting);
      else
            return FALSE;
}

GSList * beryl_settings_context_get_existing_profiles(BerylSettingsContext * context)
{
      if (context->get_existing_profiles)
            return context->get_existing_profiles();
      else
            return NULL;
}

void beryl_settings_free_profile_list(GSList * list)
{
      g_slist_foreach(list,(GFunc)g_free,NULL);
      g_slist_free(list);
}

gboolean beryl_settings_context_import_from_file(BerylSettingsContext * context, gchar * filename, gboolean overwrite)
{
      void * ini_hand=open_backend("ini");
      if (!ini_hand)
            g_error("Something pathological happened, ini load fail");
      GKeyFile * f;
      f=g_key_file_new();
      GError * e=NULL;
      g_key_file_load_from_file(f,filename,0,&e);
      if (e)
      {
            g_error_free(e);
            g_key_file_free(f);
            return FALSE;
      }
      ImportInfo i;
      i.overwrite=overwrite;
      i.context=context;
      i.readfunc=dlsym(ini_hand,"read_setting");
      gpointer save_bpp=context->backend_private_ptr;
      context->backend_private_ptr=f;
      g_slist_foreach(context->plugins,(GFunc)import_for_plugin,&i);
      context->backend_private_ptr=save_bpp;
      dlclose(ini_hand);
      g_key_file_free(f);
      return TRUE;
}

void beryl_settings_context_export_to_file(BerylSettingsContext * context, gchar * filename)
{
      void * ini_hand=open_backend("ini");
      if (!ini_hand)
            g_error("Something pathological happened, ini load fail");
      GKeyFile * f;
      gchar * s;
      f=g_key_file_new();
      ExportInfo i;
      i.context=context;
      i.writefunc=dlsym(ini_hand,"write_setting");
      gpointer save_bpp=context->backend_private_ptr;
      context->backend_private_ptr=f;
      g_slist_foreach(context->plugins,(GFunc)export_for_plugin,&i);
      context->backend_private_ptr=save_bpp;
      dlclose(ini_hand);
      s=g_key_file_to_data(f,NULL,NULL);
      g_file_set_contents(filename,s,-1,NULL);
      g_free(s);
      g_key_file_free(f);
}

gboolean beryl_setting_get_is_advanced(BerylSetting * setting)
{
      return setting->advanced;
}

void beryl_settings_set_codeset(const char* s)
{
        if (codeset)
              free(codeset);
        codeset = s ? strdup(s) : NULL;
}

GSList * beryl_settings_plugin_get_provides(BerylSettingsPlugin * plugin)
{
      return plugin->provides;
}
GSList * beryl_settings_plugin_get_requires(BerylSettingsPlugin * plugin)
{
      return plugin->requires;
}
GSList * beryl_settings_plugin_get_load_before(BerylSettingsPlugin * plugin)
{
      return plugin->load_before;
}
GSList * beryl_settings_plugin_get_load_after(BerylSettingsPlugin * plugin)
{
      return plugin->load_after;
}

GSList * beryl_settings_context_find_conflicts_for_setting(BerylSettingsContext * context, BerylSetting * setting, BerylSettingConflictType type)
{
      FindConflict f;
      f.retlist=NULL;
      if (type==BERYL_SETTING_CONFLICT_TYPE_ANY)
            for (type=BERYL_SETTING_CONFLICT_TYPE_KEY;
                        type<BERYL_SETTING_CONFLICT_TYPE_ANY;type++)
            {
                  f.type=type;
                  f.seeking_setting=NULL;
                  setting_find_conflicts(setting,&f);
            }
      else
      {
            f.type=type;
            f.seeking_setting=NULL;
            setting_find_conflicts(setting,&f);
      }
      return f.retlist;
}

GSList * beryl_settings_context_find_conflicts(BerylSettingsContext * context, BerylSettingConflictType type)
{
      FindConflict f;
      f.retlist=NULL;
      if (type==BERYL_SETTING_CONFLICT_TYPE_ANY)
            for (type=BERYL_SETTING_CONFLICT_TYPE_KEY;
                        type<BERYL_SETTING_CONFLICT_TYPE_ANY;type++)
            {
                  f.type=type;
                  f.seeking_setting=NULL;
                  g_slist_foreach(context->plugins,(GFunc)plugin_find_conflicts,&f);
            }
      else
      {
            f.type=type;
            f.seeking_setting=NULL;
            g_slist_foreach(context->plugins,(GFunc)plugin_find_conflicts,&f);
      }
      return f.retlist;
}

void beryl_settings_free_conflict_list(GSList * list)
{
      GSList * l;
      for(l=list;l;l=l->next)
      {
            BerylSettingConflict * c = l->data;
            g_slist_free(c->settings);
            free(c);
      }
      g_slist_free(list);
}

BerylSetting * beryl_settings_context_find_first_edge_owner(BerylSettingsContext * context, gint edgemask)
{
      GSList * l;
      for (l=context->plugins;l;l=l->next)
      {
            GSList * m;
            BerylSettingsPlugin * p = l->data;
            for(m=p->settings;m;m=m->next)
            {
                  BerylSetting * s=m->data;
                  if (s->type==BERYL_SETTING_TYPE_BINDING &&
                              s->info.for_bind.edge &&
                              s->value.value.as_binding.edge_mask & edgemask)
                        return s;
            }
      }
      return NULL;
}
BerylSettingsPlugin * beryl_setting_get_plugin(BerylSetting * setting)
{
      return setting->parent;
}
BerylSettingConflictType beryl_setting_conflict_get_type(BerylSettingConflict * c)
{
      return c->type;
}
GSList * beryl_setting_conflict_get_settings(BerylSettingConflict * c)
{
      return c->settings;
}

GSList * beryl_settings_context_get_active_plugins(BerylSettingsContext * c)
{
      GSList * l;
      GSList * ret = NULL;
      for (l=c->plugins;l;l=l->next)
      {
            BerylSetting * s = beryl_settings_plugin_find_setting(l->data,"____plugin_enabled",FALSE);
            if (s)
            {
                  if (s->value.value.as_bool)
                        ret=g_slist_append(ret,l->data);
            }
      }
      return ret;
}

gboolean beryl_settings_plugin_enable(BerylSettingsPlugin * p)
{
      if (!p->name)
            return FALSE;
      BerylSetting * s = beryl_settings_plugin_find_setting(p,"____plugin_enabled",FALSE);
      if (!s)
            return FALSE;
      GSList * l, * m, * n, * o;
      o = beryl_settings_context_get_active_plugins(p->context);
      for(l=p->requires;l;l=l->next)
      {
            for (m=o;m;m=m->next)
            {
                  for (n=((BerylSettingsPlugin *)m->data)->provides;n;n=n->next)
                  {
                        if (!strcmp((char *)n->data,(char *)l->data))
                              break;
                  }
                  if (n)
                        break;
            }
            if (!m)
            {
                  puts("requires");
                  puts(l->data);
                  g_slist_free(o);
                  return FALSE;
            }
      }
      for(l=p->provides;l;l=l->next)
      {
            for (m=o;m;m=m->next)
            {
                  for (n=((BerylSettingsPlugin *)m->data)->provides;n;n=n->next)
                  {
                        if (!strcmp((char *)n->data,(char *)l->data))
                              break;
                  }
                  if (n)
                        break;
            }
            if (m)
            {
                  puts("provides");
                  puts(l->data);
                  g_slist_free(o);
                  return FALSE;
            }
      }
      g_slist_free(o);
      gboolean b = TRUE;
      return beryl_setting_value_set_bool(beryl_setting_get_primary_value(s),&b);
}

gboolean beryl_settings_plugin_disable(BerylSettingsPlugin * p)
{
      if (!p->name)
            return FALSE;
      BerylSetting * s = beryl_settings_plugin_find_setting(p,"____plugin_enabled",FALSE);
      if (!s)
            return FALSE;
      GSList * l, * m, * n, * o;
      o = beryl_settings_context_get_active_plugins(p->context);
      for(l=p->provides;l;l=l->next)
      {
            for (m=o;m;m=m->next)
            {
                  for (n=((BerylSettingsPlugin *)m->data)->requires;n;n=n->next)
                  {
                        if (!strcmp((char *)n->data,(char *)l->data))
                              break;
                  }
                  if (n)
                        break;
            }
            if (m)
            {
                  puts(l->data);
                  g_slist_free(o);
                  return FALSE;
            }
      }
      g_slist_free(o);
      gboolean b = FALSE;
      return beryl_setting_value_set_bool(beryl_setting_get_primary_value(s),&b);
}

gboolean beryl_settings_plugin_get_is_enabled(BerylSettingsPlugin * p)
{
      BerylSetting * s = beryl_settings_plugin_find_setting(p,"____plugin_enabled",FALSE);
      if (!s)
            return TRUE;
      gboolean b = FALSE;
      if (beryl_setting_value_get_bool(beryl_setting_get_primary_value(s),&b))
            return b;
      else
            return TRUE;
}

gchar * beryl_settings_plugin_get_filename(BerylSettingsPlugin * p)
{
      return p->filename;
}

GSList * beryl_settings_get_backends(void)
{
      if (backends_need_init)
            fill_backends_list();
      backends_need_init=FALSE;
      return Backends;
}

gchar * beryl_settings_backend_get_name(BerylSettingsBackend * b)
{
      return b->name;
}

gchar * beryl_settings_backend_get_short_desc(BerylSettingsBackend * b)
{
      return b->short_desc;
}

gboolean beryl_settings_backend_get_supports_integration(BerylSettingsBackend * b)
{
      return b->supports_integration;
}

gboolean beryl_settings_delete_profile(BerylSettingsContext * c, gchar * profile)
{
      if (c->delete_profile)
            return (*c->delete_profile)(profile);
      return FALSE;
}

void beryl_setting_add_nofify(BerylSettingsContext * context, BerylSettingChangedNotifyFunc function)
{
      if (context)
            context->setting_changed = function;
}

gboolean beryl_setting_changed(BerylSetting *setting)
{
      BerylSettingsContext *c = setting->parent->context;

      if (!c->setting_changed)
            return FALSE;

      if (!c->read_init)
            return FALSE;
      if (!c->read_done)
            return FALSE;

      if (!c->read_init(c)) return FALSE;

      read_setting(setting,c);

      c->read_done(c);

      (*c->setting_changed)(c);

      return TRUE;
}

Generated by  Doxygen 1.6.0   Back to index