All pastes #182828 Raw Edit

Untitled

public c v1 · immutable
#182828 ·published 2006-09-26 11:45 UTC
rendered paste body
/* * Copyright (C) 2006 Quinn Storm <livinglatexkali@gmail.com> * * 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#include <gtk/gtk.h>#include <glib/gstdio.h>#define DBUS_API_SUBJECT_TO_CHANGE#include <dbus/dbus.h>#include <dbus/dbus-glib.h>#include <dbus/dbus-glib-lowlevel.h>#include <string.h>#include <malloc.h>#include <beryl.h>#include <stdlib.h>//locale stuff#include<libintl.h>#include<locale.h>#define _(String) gettext (String)#define gettext_noop(String) String#define N_(String) gettext_noop (String)typedef enum _SETOptionType{    SETString,    SETColor,    SETInt,    SETBool,    SETFloat,    SETAction,    SETList,    SETMAX} SETOptionType;gchar * SETOptionTypes[]={    "string",    "color",    "int",    "bool",    "float",    "action",    "list",};typedef union _SETOptionValue SETOptionValue;union _SETOptionValue{    gchar * s;    gint i;    gdouble f;    SETOptionValue * l;    gint c[4];    gint a[6];    gboolean b;};typedef struct _SETNumericWidgets{    GtkSpinButton * s;    GtkHScale * h;} SETNumericWidgets;gint nModifiers[]={    ShiftMask,    ControlMask,    CompAltMask,    CompSuperMask,    CompHyperMask,    CompMetaMask,    CompModeSwitchMask,    Mod1Mask,    Mod2Mask,    Mod3Mask,    Mod4Mask,    Mod5Mask,};gchar * modifiers[]={    "Shift",    "Control",    "Alt",    "Super",    "Hyper",    "Meta",    "Mode",    "Mod1",    "Mod2",    "Mod3",    "Mod4",    "Mod5",};#define NMODIFIERS (sizeof(modifiers)/sizeof(gchar *))#define MODROWS 2gchar * edges[]={    "Left",    "Right",    "Top",    "Bottom",    "Top-Left",    "Top-Right",    "Bottom-Left",    "Bottom-Right",};// intuitive layout of edge checkboxes in the tablegint edgecols[]= {    0,    2,    1,    1,    0,    2,    0,    2,};gint edgerows[]= {    1,    1,    0,    2,    0,    0,    2,    2,};typedef struct _SETActionWidgets{    GtkCheckButton  * kmod[NMODIFIERS];      // modifiers for key    GtkEntry        * key;                   // keysym(string in entrybox)    GtkCheckButton  * bmod[NMODIFIERS];      // modifiers for mouse button    GtkEntry        * but;                   // mouse button    GtkCheckButton  * b;                     // bell    GtkCheckButton  * e[SCREEN_EDGE_NUM];    // edges (checklist)} SETActionWidgets;typedef struct _SETStringListWidgets{    GtkListStore * backing;    GtkTreeView  * view;    GtkButton * add;    GtkButton * rem;    GtkButton * bro;    GtkButton * up;    GtkButton * dn;} SETStringListWidgets;typedef struct _SETStringBrowseWidgets{    GtkEntry * e;    GtkButton * b;} SETStringBrowseWidgets;typedef union _SETOptionWidgets{    GtkWidget * w;    GtkCheckButton * b;    SETStringBrowseWidgets sb;    SETNumericWidgets n;    SETActionWidgets a;    GtkWidget ** l;    SETStringListWidgets s;} SETOptionWidgets;typedef union _SETOptionRestrictions{    gchar ** s; // NULL terminated list of possible strings, NULL for anything goes    gint i[2]; // min, max    gdouble f[3]; // min, max, prec    gboolean a[4]; // button, key, edge, bell} SETOptionRestrictions;typedef struct _SETOption{    gchar * name;    gchar * section;    gchar * sdesc;    gchar * ldesc;    SETOptionType type;    SETOptionType listtype;    SETOptionValue value;    SETOptionValue defaultValue;    SETOptionRestrictions rest;    gchar ** hints; // NULL terminated list of hints    gint nValue;    gint nDValue;    SETOptionWidgets widgets;    gboolean defined;} SETOption;typedef struct _SETGroupWidget{    gchar * group;    GtkWidget * widget;    gboolean hasany;} SETGroupWidget;typedef struct _SETPage{    gchar * name;    GtkWidget * widget;} SETPage;typedef struct _SETResetOption{    SETOption * o;    gint resetType; // for action options, 0=button,1=key,2=edge,3=bell} SETResetOption;SETPage * SETOptionPages;GSList * SETOptions=NULL;GSList * reloadOptions=NULL;GKeyFile * schemaFile;GKeyFile * settingsFile;GtkListStore * pluginList;GtkTreeView * SETPluginList;GtkWidget * pluginContainer;GtkWidget * infoLabel;GtkWidget * infoContainer;gint nPages=0;gint nOthers=0;gchar ** oplugs=NULL;GtkWidget * mainWindow;static gboolean suspend_signals=FALSE;enum _SETPluginListEntry{    PluginName,    ShortDesc,    LongDesc,    Markup,    PluginIcon,    PluginEnabled,    PluginCanEnable,    PluginEntryCount};DBusConnection *dbcon;void send_option_changed_signal(gchar * section, gchar * option){    DBusMessage * mesg;    const char * sstring="section";    const char * ostring="option";    mesg = dbus_message_new_method_call("org.freedesktop.beryl",            "/org/freedesktop/beryl/settings/allscreens/reload",            "org.freedesktop.beryl","activate");    dbus_message_append_args(mesg,            DBUS_TYPE_STRING,&sstring,            DBUS_TYPE_STRING,&section,            DBUS_TYPE_STRING,&ostring,            DBUS_TYPE_STRING,&option,            DBUS_TYPE_INVALID);    dbus_connection_send(dbcon,mesg,NULL);    dbus_message_unref(mesg);}gboolean dequeue_sig(gpointer p){    if (reloadOptions)    {        SETOption * o = reloadOptions->data;        reloadOptions=g_slist_remove_all(reloadOptions,o);        send_option_changed_signal(o->section,o->name);    }    return TRUE;}void queue_option_changed(SETOption * o){    if (!g_slist_find(reloadOptions,o))        reloadOptions=g_slist_append(reloadOptions,o);}void import_key_file(GKeyFile * dest, gchar * source){    GKeyFile * f = g_key_file_new();    gchar ** gr;    gint i;    g_key_file_load_from_file(f,source,0,NULL);    gr = g_key_file_get_groups(f,NULL);    for (i=0;gr && gr[i];i++)    {        gint j;        gchar ** ke;        ke = g_key_file_get_keys(f,gr[i],NULL,NULL);        for (j=0;ke && ke[j];j++)            g_key_file_set_value(dest,gr[i],ke[j],                    g_key_file_get_value(f,gr[i],ke[j],NULL));        g_strfreev(ke);    }    g_strfreev(gr);    g_key_file_free(f);}void load_schema_files(){    GDir * d;    gchar * dpos;    gchar * temp1;    settingsFile = g_key_file_new();    temp1=g_strconcat(g_get_home_dir(),"/.beryl/settings",NULL);    g_key_file_load_from_file(settingsFile,temp1,0,NULL);    g_free(temp1);    schemaFile = g_key_file_new();    import_key_file(schemaFile,DATADIR "/beryl/settings");    import_key_file(schemaFile,DATADIR "/beryl/hints");    d=g_dir_open(DATADIR "/beryl/",0,NULL);    if (d)    {        const gchar * e;        while((e=g_dir_read_name(d)))        {            gchar * xfile;            if (g_str_has_suffix(e,".settings"))            {                xfile = g_strconcat(DATADIR "/beryl/",e,NULL);                import_key_file(schemaFile,xfile);                g_free(xfile);            }        }        g_dir_close(d);    }    dpos = g_strconcat(g_get_home_dir(),"/.beryl/plugins/",NULL);    d=g_dir_open(dpos,0,NULL);    if (d)    {        const gchar * e;        while((e=g_dir_read_name(d)))        {            gchar * xfile;            if (g_str_has_suffix(e,".settings"))            {                xfile = g_strconcat(g_get_home_dir(),"/.beryl/plugins/",e,NULL);                import_key_file(schemaFile,xfile);                g_free(xfile);            }        }        g_dir_close(d);    }    g_free(dpos);}SETOptionType string_to_type(gchar * optype){    gint i;    for (i=0;i<SETMAX;i++)    {        if (strcmp(SETOptionTypes[i],optype)==0)            return i;    }    return SETMAX;}void free_option_value(SETOption * o){    if (o->type == SETString)    {        if (o->value.s)            g_free(o->value.s);        o->value.s=NULL;    }    if (o->type == SETList && o->value.l)    {        gint i;        if (o->listtype==SETString)            for(i=0;i<o->nValue;i++)            {                if (o->value.l[i].s)                    g_free(o->value.l[i].s);            }        free(o->value.l);        o->value.l=NULL;        o->nValue=0;    }}void copy_option_from_default(SETOption * o){    memcpy(&o->value,&o->defaultValue,sizeof(SETOptionValue));    if (o->type == SETString)        o->value.s=g_strdup(o->defaultValue.s);    if (o->type == SETList)    {        gint i;        o->nValue=o->nDValue;        if (o->nValue)        {            o->value.l=malloc(sizeof(SETOptionValue)*o->nValue);            memcpy(o->value.l,o->defaultValue.l,sizeof(SETOptionValue)*o->nValue);            if (o->listtype==SETString)                for(i=0;i<o->nValue;i++)                    o->value.l[i].s=g_strdup(o->defaultValue.l[i].s);        }    }}void load_option(SETOption *o, gboolean dfl){    gchar * dkey = dfl?g_strconcat("d_",o->name,NULL):g_strdup(o->name);    SETOptionValue * v = dfl?(&o->defaultValue):(&o->value);    GKeyFile * f = dfl?schemaFile:settingsFile;    GError * e = NULL;    gint * nv = dfl?(&o->nDValue):(&o->nValue);    gboolean useDfl=FALSE;    if (!dfl)        free_option_value(o); // default values never need freed :-P    switch(o->type)    {        case SETString:            {                gchar * s;                s=g_key_file_get_string(f,o->section,dkey,NULL);                if (!s)                {                    useDfl=TRUE;                    break;                }                if (o->rest.s && !dfl)                {                    gboolean allowed=FALSE;                    gchar * e;                    gint i;                    for (i=0;(e=o->rest.s[i]);i++)                    {                        if (strcmp(e,s)==0)                            allowed=TRUE;                    }                    if (!allowed)                    {                        g_free(s);                        s=g_strdup(o->defaultValue.s);                    }                    if (o->value.s)                        g_free(o->value.s);                    v->s=s;                }                else                    v->s=s;            }            break;        case SETBool:            {                gboolean b;                b=g_key_file_get_boolean(f,o->section,dkey,&e);                if (e)                {                    useDfl=TRUE;                    break;                }                v->b=b;            }            break;        case SETInt:            {                gint i;                i=g_key_file_get_integer(f,o->section,dkey,&e);                if (e)                {                    useDfl=TRUE;                    break;                }                v->i=MAX(i,o->rest.i[0]);                v->i=MIN(v->i,o->rest.i[1]);            }            break;        case SETFloat:            {                gchar * s;                gdouble fl;                s=g_key_file_get_string(f,o->section,dkey,NULL);                if (!s)                {                    useDfl=TRUE;                    break;                }                fl=g_ascii_strtod(s,NULL);                g_free(s);                v->f=MAX(fl,o->rest.f[0]);                v->f=MIN(v->f,o->rest.f[1]);                //not bothering with prec for right now.            }            break;        case SETColor:            {                gint * i;                gsize l=0;                i=g_key_file_get_integer_list(f,o->section,dkey,&l,&e);                if (e || l!=4)                {                    if (!e)                        g_free(i);                    useDfl=TRUE;                    break;                }                v->c[0]=i[0];                v->c[1]=i[1];                v->c[2]=i[2];                v->c[3]=i[3];                if (!e && l==4)                    g_free(i);            }            break;        case SETAction:            {                gint * i;                gsize l=0;                i=g_key_file_get_integer_list(f,o->section,dkey,&l,&e);                if (e || l!=6)                {                    if (!e)                        g_free(i);                    useDfl=TRUE;                    break;                }                v->a[0]=i[0];                v->a[1]=i[1];                v->a[2]=i[2];                v->a[3]=i[3];                v->a[4]=i[4];                v->a[5]=i[5];                if (!e && l==6)                    g_free(i);            }            break;        case SETList:            {                gsize l=0;                switch(o->listtype)                {                    case SETString:                        {                            gint i;                            gchar ** s=g_key_file_get_string_list(f,o->section,dkey,&l,&e);                            if (e)                            {                                useDfl=TRUE;                                break;                            }                            //prune invalid values from s                            if (o->rest.s)                            {                                for (i=0;i<l && s[i];i++)                                {                                    gchar * e;                                    gint j;                                    gboolean keep=FALSE;                                    for (j=0;(e=o->rest.s[j]);j++)                                    {                                        if (strcmp(s[i],e)==0)                                            keep=TRUE;                                    }                                    if (!keep)                                    {                                        g_free(s[i]); // I think this is ok                                        memmove(s+i,s+i+1,                                                sizeof(gchar *)*(l-i)); // one beyond l for the NULL                                        l--;                                        i--;                                    }                                }                            }                            *nv=l;                            if (l)                                v->l=malloc(l*sizeof(SETOptionValue));                            else                                v->l=NULL;                            for (i=0;i<l;i++)                            {                                v->l[i].s=g_strdup(s[i]);                            }                            g_strfreev(s);                        }                        break;                    case SETBool:                        {                            gint i;                            gboolean * b;                            b=g_key_file_get_boolean_list(f,o->section,dkey,&l,&e);                            if (e)                            {                                useDfl=TRUE;                                break;                            }                            *nv=l;                            if (l)                                v->l=malloc(sizeof(SETOptionValue)*l);                            else                                v->l=NULL;                            for (i=0;i<l;i++)                            {                                v->l[i].b=b[i];                            }                            g_free(b);                        }                    case SETInt:                        {                            gint i;                            gint * b;                            b=g_key_file_get_integer_list(f,o->section,dkey,&l,&e);                            if (e)                            {                                useDfl=TRUE;                                break;                            }                            *nv=l;                            if (l)                                v->l=malloc(sizeof(SETOptionValue)*l);                            else                                v->l=NULL;                            for (i=0;i<l;i++)                            {                                v->l[i].i=b[i];                            }                            g_free(b);                        }                        break;                    case SETFloat:                        {                            gint i;                            gchar ** s;                            s=g_key_file_get_string_list(f,o->section,dkey,&l,&e);                            if (e)                            {                                useDfl=TRUE;                                break;                            }                            *nv=l;                            if (l)                                v->l=malloc(sizeof(SETOptionValue)*l);                            else                                v->l=NULL;                            for (i=0;i<l;i++)                            {                                v->l[i].f=g_ascii_strtod(s[i],NULL);                            }                            g_strfreev(s);                        }                        break;                    case SETColor:                        {                            gint i;                            gint * b;                            b=g_key_file_get_integer_list(schemaFile,o->section,o->name,&l,&e);                            if (e || l%4!=0)                            {                                useDfl=TRUE;                                break;                            }                            *nv=l/4;                            if (l/4)                                v->l=malloc(sizeof(SETOptionValue)*l/4);                            else                                v->l=NULL;                            for (i=0;i<l/4;i++)                            {                                v->l[i].c[0]=b[i*4];                                v->l[i].c[1]=b[i*4+1];                                v->l[i].c[2]=b[i*4+2];                                v->l[i].c[3]=b[i*4+3];                            }                            g_free(b);                        }                        break;                    case SETAction:                        {                            gint i;                            gint * b;                            b=g_key_file_get_integer_list(f,o->section,dkey,&l,&e);                            if (e || l%6!=0)                            {                                useDfl=TRUE;                                break;                            }                            *nv=l/6;                            if (l/6)                                v->l=malloc(sizeof(SETOptionValue)*l/6);                            else                                v->l=NULL;                            for (i=0;i<l/6;i++)                            {                                v->l[i].a[0]=b[i*6];                                v->l[i].a[1]=b[i*6+1];                                v->l[i].a[2]=b[i*6+2];                                v->l[i].a[3]=b[i*6+3];                                v->l[i].a[4]=b[i*6+4];                                v->l[i].a[5]=b[i*6+5];                            }                            g_free(b);                        }                        break;                    default:                        g_error("invalid t_ for %s",o->name);                }            }            break;        default:            g_error("invalid o_ for %s",o->name);    }    if (useDfl && dfl)        g_error("no d_ for %s",o->name);    else if (useDfl)        copy_option_from_default(o);    g_free(dkey);}void init_option(gchar * group, gchar * option){    SETOption * o;    gchar * val;    gchar * key;    gboolean screen;    if (g_str_has_prefix(option,"s_"))        screen=TRUE;    else if (g_str_has_prefix(option,"a_"))        screen=FALSE;    else        return;    o = malloc(sizeof(SETOption));    bzero(o,sizeof(SETOption));    o->name = g_strdup(option);    o->section=g_strdup(group);    key = g_strconcat("h_",option,NULL);    o->hints = g_key_file_get_string_list(schemaFile,o->section,key,NULL,NULL);    g_free(key);    key = g_strconcat("o_",option,NULL);    val = g_key_file_get_string(schemaFile,group,key,NULL);    if (!val)        g_error("missing o_ for %s",option); // SHOULD be impossible    o->type = string_to_type(val);    g_free(val);    g_free(key);    key=g_strconcat("n_",option,NULL);    val = g_key_file_get_string(schemaFile,group,key,NULL);    if (!val)        g_warning("missing n_ for %s",option);    else        o->sdesc=val;    g_free(key);    key=g_strconcat("l_",option,NULL);    val = g_key_file_get_string(schemaFile,group,key,NULL);    if (!val)        g_warning("missing l_ for %s",option);    else        o->ldesc = val;    g_free(key);    if (o->type==SETList)    {        key=g_strconcat("t_",option,NULL);        val=g_key_file_get_string(schemaFile,group,key,NULL);        if (!val)            g_error("list option with no t_ %s",option);        o->listtype=string_to_type(val);        g_free(val);        g_free(key);    }    if (o->type==SETString || (o->type==SETList && o->listtype==SETString))    {        key=g_strconcat("s_",option,NULL);        o->rest.s=g_key_file_get_string_list(schemaFile,group,key,NULL,NULL);        g_free(key);    }    else if (o->type==SETInt)    {        gint * i;        gsize l;        GError * e = NULL;        key=g_strconcat("s_",option,NULL);        i=g_key_file_get_integer_list(schemaFile,group,key,&l,&e);        if (!e && l==2)        {            o->rest.i[0]=i[0];            o->rest.i[1]=i[1];        }        else        {            g_error("int option with no or invalid s_ %s",option);        }    }    else if (o->type==SETFloat)    {        gchar ** s;        gsize l;        GError * e = NULL;        key=g_strconcat("s_",option,NULL);        s=g_key_file_get_string_list(schemaFile,group,key,&l,&e);        if (s)        {            if (!e && l==3)            {                o->rest.f[0]=g_ascii_strtod(s[0],NULL);                o->rest.f[1]=g_ascii_strtod(s[1],NULL);                o->rest.f[2]=g_ascii_strtod(s[2],NULL);            }            else                g_error ("float option with no or invalid s_ %s",option);            g_strfreev(s);        }        else            g_error ("float option with no or invalid s_ %s",option);    }    else if (o->type==SETAction)    {        gboolean * b;        gsize l;        GError * e = NULL;        key=g_strconcat("s_",option,NULL);        b=g_key_file_get_boolean_list(schemaFile,group,key,&l,&e);        if (!e && l==4)        {            o->rest.a[0]=b[0];            o->rest.a[1]=b[1];            o->rest.a[2]=b[2];            o->rest.a[3]=b[3];        }        else            g_error("action option with no or invalid s_ %s",option);    }    load_option(o,TRUE); // load defaults    load_option(o,FALSE);    SETOptions=g_slist_append(SETOptions,o);}void load_options_for(gchar * group){    gsize nKeys;    gint i;    gchar ** keys = g_key_file_get_keys(schemaFile,group,&nKeys,NULL);    for (i=0;i<nKeys;i++)    {        if (g_str_has_prefix(keys[i],"o_"))        {            init_option(group,keys[i]+2);        }     }    g_strfreev(keys);}void save_option(SETOption * o){    gint i;    gchar fb[G_ASCII_DTOSTR_BUF_SIZE];    gchar * fn;    switch(o->type)    {        case SETBool:            g_key_file_set_boolean(settingsFile,o->section,o->name,o->value.b);            break;        case SETInt:            g_key_file_set_integer(settingsFile,o->section,o->name,o->value.i);            break;        case SETString:            g_key_file_set_string(settingsFile,o->section,o->name,o->value.s);            break;        case SETColor:            g_key_file_set_integer_list(settingsFile,o->section,o->name,o->value.c,4);            break;        case SETAction:            g_key_file_set_integer_list(settingsFile,o->section,o->name,o->value.a,6);            break;        case SETFloat:            g_ascii_dtostr(fb,G_ASCII_DTOSTR_BUF_SIZE,o->value.f);            g_key_file_set_string(settingsFile,o->section,o->name,fb);            break;        case SETList:            switch(o->listtype)            {                case SETBool:                    {                        gboolean * b = malloc(sizeof(gboolean)*o->nValue);                        for(i=0;i<o->nValue;i++)                            b[i]=o->value.l[i].b;                        g_key_file_set_boolean_list(settingsFile,o->section,o->name,b,o->nValue);                        free(b);                    }                    break;                case SETInt:                    {                        gint * b = malloc(sizeof(gint)*o->nValue);                        for(i=0;i<o->nValue;i++)                            b[i]=o->value.l[i].i;                        g_key_file_set_integer_list(settingsFile,o->section,o->name,b,o->nValue);                        free(b);                    }                    break;                case SETColor:                    {                        gint * b = malloc(sizeof(gint)*o->nValue*4);                        for(i=0;i<o->nValue;i++)                        {                            b[i*4]=o->value.l[i].c[0];                            b[i*4+1]=o->value.l[i].c[1];                            b[i*4+2]=o->value.l[i].c[2];                            b[i*4+3]=o->value.l[i].c[3];                        }                        g_key_file_set_integer_list(settingsFile,o->section,o->name,b,o->nValue*4);                        free(b);                    }                    break;                case SETAction:                    {                        gint * b = malloc(sizeof(gint)*o->nValue*6);                        for(i=0;i<o->nValue;i++)                        {                            b[i*6]=o->value.l[i].a[0];                            b[i*6+1]=o->value.l[i].a[1];                            b[i*6+2]=o->value.l[i].a[2];                            b[i*6+3]=o->value.l[i].a[3];                            b[i*6+4]=o->value.l[i].a[4];                            b[i*6+5]=o->value.l[i].a[5];                        }                        g_key_file_set_integer_list(settingsFile,o->section,o->name,b,o->nValue*6);                        free(b);                    }                    break;                case SETString:                    {                        gchar ** s = malloc(sizeof(gchar *)*o->nValue);                        for(i=0;i<o->nValue;i++)                            s[i]=o->value.l[i].s;                        g_key_file_set_string_list(settingsFile,o->section,o->name,(const gchar **)s,o->nValue);                        free(s);                    }                    break;                case SETFloat:                    {                        gchar ** s = malloc(sizeof(gchar)*o->nValue);                        for(i=0;i<o->nValue;i++)                        {                            s[i]=malloc(G_ASCII_DTOSTR_BUF_SIZE);                            g_ascii_dtostr(s[i],G_ASCII_DTOSTR_BUF_SIZE,o->value.l[i].f);                        }                        g_key_file_set_string_list(settingsFile,o->section,o->name,(const gchar **)s,o->nValue);                        for(i=0;i<o->nValue;i++)                            free(s[i]);                        free(s);                    }                    break;                default:                    g_error("Bad list type");            }            break;        default:            g_error("invalid type in save option.");    }    fn = g_strconcat(g_get_home_dir(),"/.beryl/settings",NULL);    g_file_set_contents(fn,g_key_file_to_data(settingsFile,NULL,NULL),-1,NULL);    queue_option_changed(o);}void cb_option(GtkWidget * w, SETOption * o){    if (suspend_signals)        return;    switch(o->type)    {        case SETBool:            if (o->value.b==gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.b)))                    return;            o->value.b=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.b));            break;        case SETInt:        case SETFloat:            {                gdouble f;                if (GTK_WIDGET(w)==GTK_WIDGET(o->widgets.n.s))                {                    f=gtk_spin_button_get_value(GTK_SPIN_BUTTON(w));                }                else                {                    f=gtk_range_get_value(GTK_RANGE(w));                }                if (o->type==SETInt)                {                    if ((gint)f==o->value.i)                        return;                    o->value.i=(gint)f;                }                else                {                    if (f==o->value.f)                        return;                    o->value.f=f;                }                gtk_range_set_value(GTK_RANGE(o->widgets.n.h),f);                gtk_spin_button_set_value(GTK_SPIN_BUTTON(o->widgets.n.s),f);            }            break;        case SETString:            {                const gchar * s;                if (o->rest.s && o->rest.s[0])                    s = gtk_combo_box_get_active_text(GTK_COMBO_BOX(o->widgets.w));                else                    s = gtk_entry_get_text(GTK_ENTRY(o->widgets.w));                if (strcmp(s,o->value.s)==0)                    return;                o->value.s=g_strdup(s);            }            break;        case SETColor:            {                GdkColor c;                gint a;                gtk_color_button_get_color(GTK_COLOR_BUTTON(o->widgets.w),&c);                a=gtk_color_button_get_alpha(GTK_COLOR_BUTTON(o->widgets.w));                if (c.red!=o->value.c[0] ||                        c.green!=o->value.c[1] ||                        c.blue!=o->value.c[2] ||                        a!=o->value.c[3])                {                    o->value.c[0]=c.red;                    o->value.c[1]=c.green;                    o->value.c[2]=c.blue;                    o->value.c[3]=a;                }                else                    return;            }            break;        case SETAction:            {                gint a[6]={0,0,0,0,0,0};                gint i;                if (o->rest.a[0])                {                    a[0]=0;                    for(i=0;i<NMODIFIERS;i++)                        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.a.bmod[i])))                            a[0]|=nModifiers[i];                    a[1]=atoi(gtk_entry_get_text(GTK_ENTRY(o->widgets.a.but)));                }                if (o->rest.a[1])                {                    a[2]=0;                    for(i=0;i<NMODIFIERS;i++)                        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.a.kmod[i])))                            a[2]|=nModifiers[i];                    a[3]=XStringToKeysym(gtk_entry_get_text(GTK_ENTRY(o->widgets.a.key)));                    if (a[3]==NoSymbol)                        a[3]=0;                }                if (o->rest.a[2])                {                    a[4]=0;                    for(i=0;i<SCREEN_EDGE_NUM;i++)                    {                        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.a.e[i])))                            a[4]|=1<<i;                    }                }                if (o->rest.a[3])                {                    a[5]=gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.a.b))?1:0;                }                if ((!o->rest.a[0] || (o->value.a[0]==a[0] && o->value.a[1]==a[1])) &&                        (!o->rest.a[1] || (o->value.a[2]==a[2] && o->value.a[3]==a[3])) &&                        (!o->rest.a[2] || o->value.a[4]==a[4]) &&                        (!o->rest.a[3] || o->value.a[5]==a[5]))                    return;                for (i=0;i<6;i++)                    o->value.a[i]=a[i];            }            break;        case SETList:            {                if (o->listtype==SETString && o->rest.s && o->rest.s[0])                {                    //multiple-choice                    gint i;                    gint ns=0;                    gchar ** s;                    i=0;                    while(o->rest.s[i]) i++;                    s=malloc(sizeof(gchar *)*i);                    for (i=0;o->rest.s[i];i++)                    {                        if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(o->widgets.l[i])))                            s[ns++]=o->rest.s[i];                    }                    for (i=0;i<o->nValue;i++)                        g_free(o->value.l[i].s);                    free(o->value.l);                    o->value.l=malloc(sizeof(SETOptionValue)*ns);                    o->nValue=ns;                    for (i=0;i<ns;i++)                        o->value.l[i].s=g_strdup(s[i]);                    free(s);                    //that should work                }            }            break;        default:            g_warning("Unhandled type for %s",o->name);    }    save_option(o);}void set_info_pane(GtkWidget * w, gchar * labelMarkup){    if (strcmp(labelMarkup,"")==0)    {        gtk_widget_hide(infoContainer);    }    else    {        gtk_window_set_resizable(GTK_WINDOW(mainWindow),FALSE);        gtk_label_set_markup(GTK_LABEL(infoLabel),labelMarkup);        gtk_widget_show_all(infoContainer);        gtk_window_set_resizable(GTK_WINDOW(mainWindow),TRUE);    }}gchar * getmark(SETOption * o){    return g_markup_printf_escaped(            "<b>%s</b>\n"            "<small><i>(%s/%s)</i></small>\n"            "<small>%s</small>",            o->sdesc,            o->section,            o->name+2,            o->ldesc            );}GtkWidget * my_label_new(gchar * t){    GtkWidget * w = gtk_label_new(t);    gtk_misc_set_alignment(GTK_MISC(w),0,0);    return w;}void set_widgets_from_option(SETOption * o){    suspend_signals=TRUE;    switch(o->type)    {        case SETBool:            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.w),o->value.b);            break;        case SETString:            if (o->rest.s && o->rest.s[0])            {                gint i;                for (i=0;o->rest.s[i];i++)                {                    if (strcmp(o->rest.s[i],o->value.s)==0)                        gtk_combo_box_set_active(GTK_COMBO_BOX(o->widgets.w),i);                }            }            else                gtk_entry_set_text(GTK_ENTRY(o->widgets.w),o->value.s);            break;        case SETInt:        case SETFloat:            gtk_range_set_value(GTK_RANGE(o->widgets.n.h),                    (o->type==SETInt?o->value.i:o->value.f));            gtk_spin_button_set_value(GTK_SPIN_BUTTON(o->widgets.n.s),                    (o->type==SETInt?o->value.i:o->value.f));            break;        case SETColor:            {                GdkColor c;                c.red=o->value.c[0];                c.green=o->value.c[1];                c.blue=o->value.c[2];                gtk_color_button_set_color(GTK_COLOR_BUTTON(o->widgets.w),&c);                gtk_color_button_set_alpha(GTK_COLOR_BUTTON(o->widgets.w),                        o->value.c[3]);            }            break;        case SETAction:            if (o->rest.a[0])            {                gint i;                for(i=0;i<NMODIFIERS;i++)                {                    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.a.bmod[i]),                            (o->value.a[0] & nModifiers[i]));                }                gtk_entry_set_text(GTK_ENTRY(o->widgets.a.but),o->value.a[1]?                        g_strdup_printf("%d",o->value.a[1]):_("Disabled"));            }            if (o->rest.a[1])            {                gint i;                gchar * s;                for(i=0;i<NMODIFIERS;i++)                {                    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.a.kmod[i]),                            (o->value.a[2] & nModifiers[i]));                }                s=XKeysymToString(o->value.a[3]);                if (!s)                {                    o->value.a[2]=0;                    s="Disabled";                }                gtk_entry_set_text(GTK_ENTRY(o->widgets.a.key),s);            }            if (o->rest.a[2])            {                gint i;                for (i=0;i<SCREEN_EDGE_NUM;i++)                {                    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.a.e[i])                            ,(o->value.a[4]&(1<<i))?TRUE:FALSE);                }            }            if (o->rest.a[3])            {                gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.a.b),o->value.a[5]);            }            break;        case SETList:            if (o->listtype==SETString && o->rest.s && o->rest.s[0])            {                gint i,j;                for (i=0;o->rest.s[i];i++)                {                    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.l[i]),FALSE);                    for (j=0;j<o->nValue;j++)                    {                        if (strcmp(o->value.l[j].s,o->rest.s[i])==0)                            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(o->widgets.l[i]),TRUE);                    }                }            }            else if (o->listtype==SETString)            {                gint i;                gtk_list_store_clear(o->widgets.s.backing);                for (i=0;i<o->nValue;i++)                {                    GtkTreeIter it;                    gtk_list_store_append(o->widgets.s.backing,&it);                    gtk_list_store_set(o->widgets.s.backing,&it,0,o->value.l[i].s,-1);                }            }        default:            break;    }    suspend_signals=FALSE;}void reset_option(GtkWidget * but, SETResetOption * ro){    SETOption * o = ro->o;    if (o->type==SETAction)    {        switch(ro->resetType)        {            case 0:                o->value.a[0]=o->defaultValue.a[0];                o->value.a[1]=o->defaultValue.a[1];                break;            case 1:                o->value.a[2]=o->defaultValue.a[2];                o->value.a[3]=o->defaultValue.a[3];                break;            case 2:                o->value.a[4]=o->defaultValue.a[4];                break;            case 3:                o->value.a[5]=o->defaultValue.a[5];                break;        }    }    else        copy_option_from_default(o);    set_widgets_from_option(o);    save_option(o);}gboolean has_hint(SETOption * o, const gchar * hint){    gint i;    for (i=0;o->hints && o->hints[i];i++)    {        if (strcmp(o->hints[i],hint)==0)            return TRUE;    }    return FALSE;}    static voidcb_preview (GtkFileChooser *file_chooser, gpointer data){    GtkWidget *preview;    char *filename;    GdkPixbuf *pixbuf;    gboolean have_preview;    preview = GTK_WIDGET (data);    filename = gtk_file_chooser_get_preview_filename (file_chooser);    pixbuf = NULL;    have_preview = FALSE;    if (filename)    {        pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL);        have_preview = (pixbuf != NULL);        g_free (filename);        if (pixbuf)            gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);    }    if (pixbuf)        g_object_unref (pixbuf);    gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);}void modify_sl(SETOption * o){    //re-write the o->nValue/o->value.l based on o->widgets.s.backing    gint i;    GtkTreeIter it;    if (suspend_signals)        return;    if (o->nValue)    {        for (i=0;i<o->nValue;i++)        {            g_free(o->value.l[i].s);        }        free(o->value.l);    }    //now we have to figure out how many rows...    o->nValue=gtk_tree_model_iter_n_children(GTK_TREE_MODEL(o->widgets.s.backing),NULL);    if (o->nValue)    {        o->value.l=malloc(sizeof(SETOptionValue)*o->nValue);        for (i=0;i<o->nValue;i++)        {            gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(o->widgets.s.backing),&it,NULL,i);            gtk_tree_model_get(GTK_TREE_MODEL(o->widgets.s.backing),&it,0,&o->value.l[i].s,-1);        }    }    else    {        o->value.l=NULL;    }    save_option(o);}void cb_browse(GtkWidget * w, SETOption * o){    //make up a file widget    GtkWidget * fd;    gchar * titl=g_strconcat(_("Browse for "),_(o->sdesc),NULL);    fd = gtk_file_chooser_dialog_new(titl,GTK_WINDOW(mainWindow),            has_hint(o,_("directory"))?GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER:            GTK_FILE_CHOOSER_ACTION_OPEN,            GTK_STOCK_CANCEL,GTK_RESPONSE_CANCEL,            GTK_STOCK_OPEN,GTK_RESPONSE_ACCEPT,NULL);    g_free(titl);    if (has_hint(o,"image"))    {        GtkFileFilter * f;        GtkWidget * pr;        f = gtk_file_filter_new();        if (has_hint(o,"pngonly"))        {            gtk_file_filter_set_name(f,"PNG Images");        }        else        {            gtk_file_filter_set_name(f,_("Beryl Image Types (PNG,SVG)"));            gtk_file_filter_add_mime_type(f,"image/svg");            gtk_file_filter_add_pattern(f,"*.svg");            gtk_file_filter_add_pattern(f,"*.SVG");        }        gtk_file_filter_add_mime_type(f,"image/png");        gtk_file_filter_add_pattern(f,"*.png");        gtk_file_filter_add_pattern(f,"*.PNG");        gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(fd),f);        gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(fd),f);        pr = gtk_image_new();        gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(fd),pr);        g_signal_connect(fd,_("update-preview"),G_CALLBACK(cb_preview),pr);    }    if (o->type == SETString)        if (g_file_test(gtk_entry_get_text(o->widgets.sb.e),G_FILE_TEST_EXISTS))            gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(fd),gtk_entry_get_text(o->widgets.sb.e));    if (gtk_dialog_run(GTK_DIALOG(fd))==GTK_RESPONSE_ACCEPT)    {        gchar * s;        s=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(fd));        if (o->type == SETString)            gtk_entry_set_text(o->widgets.sb.e,s);        else        {            GtkTreeIter it;            GtkTreeSelection * se = gtk_tree_view_get_selection(o->widgets.s.view);            if (suspend_signals)                return;            gtk_tree_selection_unselect_all(se);            gtk_list_store_append(o->widgets.s.backing,&it);            gtk_list_store_set(o->widgets.s.backing,&it,0,s,-1);            gtk_tree_selection_select_iter(se,&it);            modify_sl(o);        }        g_free(s);    }    gtk_widget_destroy(fd);}GtkWidget * make_info_button_full(SETOption * o,gint rt){    GtkWidget * but;    GtkWidget * img;    GtkWidget * hb;    SETResetOption * ro = malloc(sizeof(SETResetOption));    gboolean str=((o->type==SETAction && rt!=3) || o->type==SETList);    if (str)        hb = gtk_vbox_new(FALSE,2);    else        hb = gtk_hbox_new(TRUE,2);    but = gtk_button_new();    img = gtk_image_new_from_stock(GTK_STOCK_INFO,GTK_ICON_SIZE_BUTTON);    gtk_container_add(GTK_CONTAINER(but),img);    g_signal_connect(but,"clicked",G_CALLBACK(set_info_pane),getmark(o));    gtk_box_pack_start(GTK_BOX(hb),but,str,str,0);    but = gtk_button_new();    img = gtk_image_new_from_stock(GTK_STOCK_CLEAR,GTK_ICON_SIZE_BUTTON);    gtk_container_add(GTK_CONTAINER(but),img);    ro->o=o;    ro->resetType=rt;    g_signal_connect(but,"clicked",G_CALLBACK(reset_option),ro);    gtk_box_pack_start(GTK_BOX(hb),but,str,str,0);    return hb;}GtkWidget * make_info_button(SETOption * o){    return make_info_button_full(o,0);}void do_if_toggle_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (o->type==SETBool && strcmp(o->section,w->group)==0)    {        GtkWidget * cbox;        GtkWidget * box;        box = gtk_hbox_new(FALSE,2);        cbox = gtk_check_button_new_with_label(o->sdesc);        gtk_box_pack_start(GTK_BOX(w->widget),box,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(box),make_info_button(o),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(box),cbox,TRUE,TRUE,0);        o->widgets.w=cbox;        g_signal_connect(cbox,"toggled",G_CALLBACK(cb_option),o);        o->defined=TRUE;        set_widgets_from_option(o);        w->hasany=TRUE;    }}void do_if_numeric_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if ((o->type==SETInt || o->type==SETFloat) && strcmp(o->section,w->group)==0)    {        GtkWidget * slid;        GtkWidget * spun;        GtkWidget * box;        GtkWidget * slidbox;        gdouble min = (o->type==SETInt?o->rest.i[0]:o->rest.f[0]);        gdouble max = (o->type==SETInt?o->rest.i[1]:o->rest.f[1]);        gdouble pre = (o->type==SETInt?1:o->rest.f[2]);        slid = gtk_hscale_new_with_range(min,max,pre);        spun = gtk_spin_button_new_with_range(min,max,pre);        box = gtk_hbox_new(FALSE,2);        slidbox = gtk_vbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(w->widget),box,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(box),make_info_button(o),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(box),slidbox,TRUE,TRUE,0);        gtk_box_pack_start(GTK_BOX(box),spun,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(slidbox),my_label_new(o->sdesc),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(slidbox),slid,FALSE,FALSE,0);        o->widgets.n.h=GTK_HSCALE(slid);        o->widgets.n.s=GTK_SPIN_BUTTON(spun);        gtk_scale_set_draw_value(GTK_SCALE(slid),FALSE);        gtk_range_set_update_policy(GTK_RANGE(slid),GTK_UPDATE_DISCONTINUOUS);        gtk_spin_button_set_update_policy(GTK_SPIN_BUTTON(spun),GTK_UPDATE_IF_VALID);        g_signal_connect(slid,"value-changed",G_CALLBACK(cb_option),o);        g_signal_connect(spun,"value-changed",G_CALLBACK(cb_option),o);        o->defined=TRUE;        set_widgets_from_option(o);        w->hasany=TRUE;    }}void do_if_string_choice_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if ((o->type==SETString) && strcmp(o->section,w->group)==0 && o->rest.s && o->rest.s[0])    {        GtkWidget * hbox = gtk_hbox_new(FALSE,2);        GtkWidget * vbox = gtk_vbox_new(FALSE,2);        gint i;        gtk_box_pack_start(GTK_BOX(w->widget),hbox,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),make_info_button(o),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),vbox,TRUE,TRUE,0);        gtk_box_pack_start(GTK_BOX(vbox),my_label_new(o->sdesc),FALSE,FALSE,0);        o->widgets.w=gtk_combo_box_new_text();        for (i=0;o->rest.s[i];i++)        {            gtk_combo_box_append_text(GTK_COMBO_BOX(o->widgets.w),o->rest.s[i]);        }        set_widgets_from_option(o);        g_signal_connect(o->widgets.w,"changed",G_CALLBACK(cb_option),o);        gtk_box_pack_start(GTK_BOX(vbox),o->widgets.w,FALSE,FALSE,0);        o->defined=TRUE;        w->hasany=TRUE;    }}void do_if_string_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if ((o->type==SETString) && strcmp(o->section,w->group)==0 && (!o->rest.s || !o->rest.s[0]))    {        GtkWidget * hbox = gtk_hbox_new(FALSE,2);        GtkWidget * vbox = gtk_vbox_new(FALSE,2);        GtkWidget * hbox2 = gtk_hbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(w->widget),hbox,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),make_info_button(o),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),vbox,TRUE,TRUE,0);        gtk_box_pack_start(GTK_BOX(vbox),my_label_new(o->sdesc),FALSE,FALSE,0);        o->widgets.w = gtk_entry_new();        if (!o->value.s)            o->value.s=g_strdup(""); // wuh?        set_widgets_from_option(o);        g_signal_connect(o->widgets.w,"changed",G_CALLBACK(cb_option),o);        gtk_box_pack_start(GTK_BOX(hbox2),o->widgets.w,TRUE,TRUE,0);        if (has_hint(o,"file"))        {            o->widgets.sb.b=GTK_BUTTON(gtk_button_new_with_label(_("Browse")));            gtk_button_set_image(o->widgets.sb.b,gtk_image_new_from_stock(GTK_STOCK_OPEN,GTK_ICON_SIZE_BUTTON));            gtk_box_pack_start(GTK_BOX(hbox2),GTK_WIDGET(o->widgets.sb.b),FALSE,FALSE,0);            g_signal_connect(o->widgets.sb.b,"clicked",G_CALLBACK(cb_browse),o);        }        gtk_box_pack_start(GTK_BOX(vbox),hbox2,FALSE,FALSE,0);        o->defined=TRUE;        w->hasany=TRUE;    }}void do_if_color_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if ((o->type==SETColor) && strcmp(o->section,w->group)==0)    {        GtkWidget * hbox;        GtkWidget * cbut;        hbox = gtk_hbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(w->widget),hbox,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),make_info_button(o),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),my_label_new(o->sdesc),TRUE,TRUE,0);        cbut=gtk_color_button_new();        gtk_color_button_set_use_alpha(GTK_COLOR_BUTTON(cbut),TRUE);        gtk_box_pack_start(GTK_BOX(hbox),cbut,FALSE,FALSE,0);        o->widgets.w=cbut;        g_signal_connect(cbut,"color-set",G_CALLBACK(cb_option),o);        o->defined=TRUE;        set_widgets_from_option(o);        w->hasany=TRUE;    }}void do_if_action_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if ((o->type==SETAction) && strcmp(o->section,w->group)==0)    {        if (!o->rest.a[0] &&                !o->rest.a[1] &&                !o->rest.a[2] &&                !o->rest.a[3])        {            o->defined=TRUE;            return;            //these are dbus-only calls        }        o->defined=TRUE;        w->hasany=TRUE;        set_widgets_from_option(o);    }}void do_if_bell_group(SETOption * o, SETGroupWidget * w){    if ((o->type==SETAction) && strcmp(o->section,w->group)==0)    {        if (o->rest.a[3])        {            GtkWidget * hbox = gtk_hbox_new(FALSE,2);            gtk_box_pack_start(GTK_BOX(w->widget),hbox,FALSE,FALSE,0);            gtk_box_pack_start(GTK_BOX(hbox),make_info_button_full(o,3),FALSE,FALSE,0);            o->widgets.a.b=GTK_CHECK_BUTTON(gtk_check_button_new_with_label(                        g_strconcat(_(o->sdesc),_(" on System Bell"),NULL)));            gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(o->widgets.a.b),TRUE,TRUE,0);            g_signal_connect(o->widgets.a.b,"toggled",G_CALLBACK(cb_option),o);            w->hasany=TRUE;        }    }}void make_key_button_stuff(SETOption * o, SETGroupWidget * w, gint p){    GtkEntry * entry;    GtkCheckButton ** mods;     gint i;    GtkWidget * tab;    GtkWidget * vbox2;    GtkWidget * hbox2;    GtkWidget * hbox;    GtkWidget * fram;    if (p==1)        mods=o->widgets.a.kmod;    else        mods=o->widgets.a.bmod;    fram = gtk_frame_new(o->sdesc);    gtk_box_pack_start(GTK_BOX(w->widget),fram,FALSE,FALSE,0);    hbox = gtk_hbox_new(FALSE,2);    gtk_container_add(GTK_CONTAINER(fram),hbox);    gtk_box_pack_start(GTK_BOX(hbox),make_info_button_full(o,p),FALSE,FALSE,0);    vbox2 = gtk_vbox_new(FALSE,2);    gtk_box_pack_start(GTK_BOX(hbox),vbox2,TRUE,TRUE,0);    entry = GTK_ENTRY(gtk_entry_new());    if (p==1)        o->widgets.a.key=entry;    else        o->widgets.a.but=entry;    gtk_entry_set_width_chars(entry,8);    hbox2=gtk_hbox_new(FALSE,2);    gtk_box_pack_start(GTK_BOX(vbox2),hbox2,FALSE,FALSE,0);    if (o->value.a[3]==0)        o->value.a[2]=0;    tab = gtk_table_new(0,0,FALSE);    gtk_box_pack_start(GTK_BOX(hbox2),my_label_new(_("Modifier Keys:")),FALSE,FALSE,0);    gtk_box_pack_start(GTK_BOX(hbox2),tab,TRUE,TRUE,0);    for(i=0;i<NMODIFIERS;i++)    {        gint col = (i%(NMODIFIERS/MODROWS));        gint row = (i/(NMODIFIERS/MODROWS));        mods[i]=GTK_CHECK_BUTTON(gtk_check_button_new_with_label(modifiers[i]));        g_signal_connect(mods[i],"toggled",G_CALLBACK(cb_option),o);        gtk_table_attach_defaults(GTK_TABLE(tab),GTK_WIDGET(mods[i]),                col,col+1,row,row+1);    }    hbox2=gtk_hbox_new(FALSE,2);    gtk_box_pack_start(GTK_BOX(vbox2),hbox2,FALSE,FALSE,0);    gtk_box_pack_start(GTK_BOX(hbox2),gtk_label_new(p==1?_("Key Name:"):_("Button Number:")),FALSE,FALSE,0);    gtk_box_pack_start(GTK_BOX(hbox2),GTK_WIDGET(entry),TRUE,TRUE,0);    g_signal_connect(entry,"changed",G_CALLBACK(cb_option),o);}void do_if_key_group(SETOption * o, SETGroupWidget * w){    if ((o->type==SETAction) && strcmp(o->section,w->group)==0)    {        if (o->rest.a[1])        {            make_key_button_stuff(o,w,1);            w->hasany=TRUE;        }    }}void do_if_button_group(SETOption * o, SETGroupWidget * w){    if ((o->type==SETAction) && strcmp(o->section,w->group)==0)    {        if (o->rest.a[0])        {            make_key_button_stuff(o,w,0);            w->hasany=TRUE;        }    }}void do_if_edge_group(SETOption * o, SETGroupWidget * w){    if ((o->type==SETAction) && strcmp(o->section,w->group)==0)    {        if (o->rest.a[2])        {            gint i;            GtkWidget * fram2;            GtkWidget * tab;            GtkWidget * hbox;            fram2=gtk_frame_new(o->sdesc);            tab=gtk_table_new(0,0,FALSE);            gtk_box_pack_start(GTK_BOX(w->widget),fram2,FALSE,FALSE,0);            hbox = gtk_hbox_new(FALSE,2);            gtk_container_add(GTK_CONTAINER(fram2),hbox);            gtk_box_pack_start(GTK_BOX(hbox),make_info_button_full(o,2),FALSE,FALSE,0);            gtk_box_pack_start(GTK_BOX(hbox),tab,TRUE,TRUE,0);            for (i=0;i<SCREEN_EDGE_NUM;i++)            {                o->widgets.a.e[i]=GTK_CHECK_BUTTON(gtk_check_button_new_with_label(edges[i]));                gtk_table_attach_defaults(GTK_TABLE(tab),GTK_WIDGET(o->widgets.a.e[i]),edgecols[i],edgecols[i]+1,edgerows[i],edgerows[i]+1);                g_signal_connect(o->widgets.a.e[i],"toggled",G_CALLBACK(cb_option),o);            }            w->hasany=TRUE;        }    }}#define OPT_PER_LINE 3void do_if_option_list_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (strcmp(o->section,w->group)==0 && o->type==SETList && o->listtype==SETString && o->rest.s && o->rest.s[0])    {        GtkWidget * hbox, *vbox, *tabl, *fram;        gint i, l=-1, c=0;        hbox = gtk_hbox_new(FALSE,2);        fram = gtk_frame_new(o->sdesc);        gtk_box_pack_start(GTK_BOX(w->widget),fram,FALSE,FALSE,0);        gtk_container_add(GTK_CONTAINER(fram),hbox);        gtk_box_pack_start(GTK_BOX(hbox),make_info_button(o),FALSE,FALSE,0);        vbox = gtk_vbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(hbox),vbox,TRUE,TRUE,0);        tabl=gtk_table_new(OPT_PER_LINE,1,TRUE);        gtk_box_pack_start(GTK_BOX(vbox),tabl,FALSE,FALSE,0);        i=0;        while(o->rest.s[i]) i++;        o->widgets.l=malloc(sizeof(GtkWidget *)*i);        for (i=0;o->rest.s[i];i++)        {            GtkWidget * cbut;            if (i%OPT_PER_LINE==0)            {                l++;                c=0;            }            else                c++;            cbut = gtk_check_button_new_with_label(o->rest.s[i]);            gtk_table_attach_defaults(GTK_TABLE(tabl),cbut,c,c+1,l,l+1);            o->widgets.l[i]=cbut;            g_signal_connect(cbut,"toggled",G_CALLBACK(cb_option),o);        }        set_widgets_from_option(o);        o->defined=TRUE;        w->hasany=TRUE;    }}void cb_sl_edited(GtkWidget * w, gchar * treepath, gchar * value, SETOption * o){    GtkTreeIter it;    if (suspend_signals)        return;    gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(o->widgets.s.backing),&it,treepath);    gtk_list_store_set(o->widgets.s.backing,&it,0,value,-1);    //modify_sl(o);}void cb_sl_select(GtkTreeSelection * sel, SETOption * o){    GtkTreeIter it;    GtkTreeModel * mod;    gboolean p;    p=gtk_tree_selection_get_selected(sel,&mod,&it);    gtk_widget_set_sensitive(GTK_WIDGET(o->widgets.s.rem),p);    gtk_widget_set_sensitive(GTK_WIDGET(o->widgets.s.up),p);    gtk_widget_set_sensitive(GTK_WIDGET(o->widgets.s.dn),p);}void cb_sl_add(GtkWidget * w, SETOption * o){    GtkTreeIter it;    GtkTreeSelection * s = gtk_tree_view_get_selection(o->widgets.s.view);    if (suspend_signals)        return;    gtk_tree_selection_unselect_all(s);    gtk_list_store_append(o->widgets.s.backing,&it);    gtk_list_store_set(o->widgets.s.backing,&it,0,"<New Value>",-1);    gtk_tree_selection_select_iter(s,&it);}void cb_sl_rem(GtkWidget * w, SETOption * o){    GtkTreeIter it;    GtkTreeModel * mod;    GtkTreeSelection * s = gtk_tree_view_get_selection(o->widgets.s.view);    if (suspend_signals)        return;    if (gtk_tree_selection_get_selected(s,&mod,&it))        gtk_list_store_remove(GTK_LIST_STORE(mod),&it);}void cb_row_changed(GtkWidget * w, GtkTreePath * p, GtkTreeIter * i, SETOption *o){    if (suspend_signals)        return;    modify_sl(o);}void cb_row_del(GtkWidget * w, GtkTreePath * p, SETOption *o){    if (suspend_signals)        return;    modify_sl(o);}void move_item(SETOption * o, gboolean up){    GtkTreeIter it;    GtkTreeModel * mod;    GtkTreeSelection * s = gtk_tree_view_get_selection(o->widgets.s.view);    if (suspend_signals)        return;    if (gtk_tree_selection_get_selected(s,&mod,&it))    {        GtkTreeIter nit;        if (up)        {            gchar * s = gtk_tree_model_get_string_from_iter(mod,&it);            GtkTreePath * p = gtk_tree_path_new_from_string(s);            g_free(s);            if (!gtk_tree_path_prev(p))            {                g_free(p);                return;            }            s=gtk_tree_path_to_string(p);            gtk_tree_model_get_iter_from_string(mod,&nit,s);            g_free(s);        }        else        {            nit=it;            if (!gtk_tree_model_iter_next(mod,&nit))                return;        }        gtk_list_store_swap(GTK_LIST_STORE(mod),&it,&nit);    }}void cb_move_up(GtkWidget * w, SETOption * o){    move_item(o,TRUE);}void cb_move_dn(GtkWidget * w, SETOption * o){    move_item(o,FALSE);}void do_if_string_list_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (strcmp(o->section,w->group)==0 && o->type==SETList &&             o->listtype==SETString && (!o->rest.s || !o->rest.s[0]))    {        GtkWidget * hbox;        GtkCellRenderer * celr;        GtkWidget * fram;        GtkTreeViewColumn * col;        GtkScrolledWindow * win;        GtkWidget * vbox;        if (strcmp(o->section,"_")==0 && strcmp(o->name,"a_active_plugins")==0)        {            o->defined=TRUE;            return;        }        fram = gtk_frame_new(o->sdesc);        hbox = gtk_hbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(w->widget),fram,FALSE,FALSE,0);        gtk_container_add(GTK_CONTAINER(fram),hbox);        gtk_box_pack_start(GTK_BOX(hbox),make_info_button(o),FALSE,FALSE,0);        o->widgets.s.backing=gtk_list_store_new(1,G_TYPE_STRING);        celr = GTK_CELL_RENDERER(gtk_cell_renderer_text_new());        g_signal_connect(celr,"edited",G_CALLBACK(cb_sl_edited),o);        g_object_set(celr,"editable",TRUE,NULL);        col = gtk_tree_view_column_new_with_attributes(o->sdesc,GTK_CELL_RENDERER(celr),"text",0,NULL);        o->widgets.s.view=GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(o->widgets.s.backing)));        gtk_tree_view_set_reorderable(o->widgets.s.view,TRUE);        gtk_tree_view_set_headers_visible(o->widgets.s.view,FALSE);        gtk_tree_view_append_column(o->widgets.s.view,col);        win = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL,NULL));        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);        gtk_container_add(GTK_CONTAINER(win),GTK_WIDGET(o->widgets.s.view));        gtk_box_pack_start(GTK_BOX(hbox),GTK_WIDGET(win),TRUE,TRUE,0);        o->widgets.s.add=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_ADD));        if (has_hint(o,"file"))        {            o->widgets.s.bro=GTK_BUTTON(gtk_button_new_with_label(_("Browse")));            gtk_button_set_image(o->widgets.s.bro,gtk_image_new_from_stock(                        GTK_STOCK_OPEN,GTK_ICON_SIZE_BUTTON));            g_signal_connect(o->widgets.s.bro,"clicked",G_CALLBACK(cb_browse),o);        }        o->widgets.s.rem=GTK_BUTTON(gtk_button_new_from_stock(GTK_STOCK_DELETE));        vbox = gtk_vbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(hbox),vbox,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(                    o->widgets.s.up=GTK_BUTTON(gtk_button_new())),FALSE,FALSE,0);        gtk_box_pack_end(GTK_BOX(vbox),GTK_WIDGET(                    o->widgets.s.dn=GTK_BUTTON(gtk_button_new())),FALSE,FALSE,0);        gtk_container_add(GTK_CONTAINER(o->widgets.s.up),                gtk_image_new_from_stock(GTK_STOCK_GO_UP,GTK_ICON_SIZE_BUTTON));        gtk_container_add(GTK_CONTAINER(o->widgets.s.dn),                gtk_image_new_from_stock(GTK_STOCK_GO_DOWN,GTK_ICON_SIZE_BUTTON));        gtk_widget_set_sensitive(GTK_WIDGET(o->widgets.s.rem),FALSE);        gtk_widget_set_sensitive(GTK_WIDGET(o->widgets.s.up),FALSE);        gtk_widget_set_sensitive(GTK_WIDGET(o->widgets.s.dn),FALSE);        vbox = gtk_vbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(hbox),vbox,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(o->widgets.s.add),FALSE,FALSE,0);        if (has_hint(o,"file"))            gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(o->widgets.s.bro),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(o->widgets.s.rem),FALSE,FALSE,0);        g_signal_connect(gtk_tree_view_get_selection(o->widgets.s.view),"changed",                G_CALLBACK(cb_sl_select),o);        g_signal_connect(o->widgets.s.add,"clicked",G_CALLBACK(cb_sl_add),o);        g_signal_connect(o->widgets.s.rem,"clicked",G_CALLBACK(cb_sl_rem),o);        g_signal_connect(o->widgets.s.up,"clicked",G_CALLBACK(cb_move_up),o);        g_signal_connect(o->widgets.s.dn,"clicked",G_CALLBACK(cb_move_dn),o);        gtk_tree_view_set_rules_hint(o->widgets.s.view,TRUE);        set_widgets_from_option(o);        g_signal_connect(o->widgets.s.backing,"row-changed",G_CALLBACK(cb_row_changed),o);        g_signal_connect(o->widgets.s.backing,"row-inserted",G_CALLBACK(cb_row_changed),o);        g_signal_connect(o->widgets.s.backing,"row-deleted",G_CALLBACK(cb_row_del),o);        o->defined=TRUE;        w->hasany=TRUE;    }}void do_if_command_string_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (has_hint(o,"command"))        do_if_string_group(o,w);}void do_if_simple_string_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (!has_hint(o,"file") && !has_hint(o,"command"))        do_if_string_group(o,w);}void do_if_file_string_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (has_hint(o,"file"))    {        do_if_string_group(o,w);        do_if_string_list_group(o,w);    }}void do_if_undefined_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    if (strcmp(o->section,w->group)==0 && !(o->defined))    {        //undefined        GtkWidget * hbox;        hbox=gtk_hbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(w->widget),hbox,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),make_info_button(o),FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),my_label_new(o->sdesc),TRUE,TRUE,0);        o->widgets.w=hbox;        w->hasany=TRUE;    }}void do_if_choice_option_group(SETOption * o, SETGroupWidget * w){    if (o->defined) return;    do_if_toggle_group(o,w);    do_if_string_choice_group(o,w);    do_if_option_list_group(o,w);    do_if_bell_group(o,w);}void setup_actions(gchar * group){    SETGroupWidget z;    z.group=group;    z.widget=NULL;    z.hasany=FALSE;    g_slist_foreach(SETOptions,(GFunc)do_if_action_group,&z);}void do_page(gchar * group,GFunc func,gchar * label, GtkWidget * notebook){    SETGroupWidget z;    GtkWidget * scrol = gtk_scrolled_window_new(NULL,NULL);    gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrol)            ,GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC);    GtkWidget * vbox = gtk_vbox_new(FALSE,6);    gtk_container_set_border_width(GTK_CONTAINER(vbox),4);    z.group=group;    z.widget=vbox;    z.hasany=FALSE;    g_slist_foreach(SETOptions,func,&z);    gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrol),vbox);    if (z.hasany)        gtk_notebook_append_page(GTK_NOTEBOOK(notebook),                scrol,gtk_label_new(label));}void do_option_page(gchar * group, GtkWidget * notebook){    load_options_for(group);    //okay now we can lay out a notebook    gtk_notebook_set_scrollable(GTK_NOTEBOOK(notebook),TRUE);    do_page(group,(GFunc)do_if_choice_option_group,_("Choices"),notebook);    do_page(group,(GFunc)do_if_numeric_group,_("Numeric Values"),notebook);    do_page(group,(GFunc)do_if_command_string_group,_("Commands"),notebook);    do_page(group,(GFunc)do_if_simple_string_group,_("Strings"),notebook);    do_page(group,(GFunc)do_if_file_string_group,_("Filenames"),notebook);    do_page(group,(GFunc)do_if_color_group,_("Colors"),notebook);    do_page(group,(GFunc)do_if_key_group,_("Keyboard"),notebook);    do_page(group,(GFunc)do_if_button_group,_("Mouse"),notebook);    do_page(group,(GFunc)do_if_edge_group,_("Screen Edges & Corners"),notebook);    do_page(group,(GFunc)do_if_string_list_group,_("String Lists"),notebook);    setup_actions(group);    //gtk_notebook_append_page(GTK_NOTEBOOK(notebook),    //        do_page(group,(GFunc)do_if_undefined_group),gtk_label_new("Unhandled"));}void set_plugin_active(gchar * plugin,gboolean active){    GtkTreeIter it;    gboolean k;    for(k=gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pluginList),&it);k;            k=gtk_tree_model_iter_next(GTK_TREE_MODEL(pluginList),&it))    {        gchar * pl;        gtk_tree_model_get(GTK_TREE_MODEL(pluginList),&it,PluginName,&pl,-1);        if (strcmp(pl,plugin)==0)            gtk_list_store_set(pluginList,&it,PluginEnabled,active,-1);        g_free(pl);    }}gboolean get_plugin_active(gchar * plugin){    GtkTreeIter it;    gboolean k,b;    if (strcmp(plugin,"dbus")==0)        return TRUE;    if (strcmp(plugin,"settings")==0)        return TRUE;    b=FALSE;    for(k=gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pluginList),&it);k;            k=gtk_tree_model_iter_next(GTK_TREE_MODEL(pluginList),&it))    {        gchar * pl;        gtk_tree_model_get(GTK_TREE_MODEL(pluginList),&it,PluginName,&pl,-1);        if (strcmp(pl,plugin)==0)        {            gtk_tree_model_get(GTK_TREE_MODEL(pluginList),&it,PluginEnabled,&b,-1);        }        g_free(pl);    }    return b;}void doing_active_plugins(SETOption * o, gpointer p){    if (strcmp(o->name,"a_active_plugins")==0 && strcmp(o->section,"_")==0)    {        //o is of type list[string]        gint i;        for(i=0;i<o->nValue;i++)        {            //set the plugins active            //by first finding them...            GtkTreeIter it;            gboolean k;            for(k=gtk_tree_model_get_iter_first(GTK_TREE_MODEL(pluginList),&it);k;                    k=gtk_tree_model_iter_next(GTK_TREE_MODEL(pluginList),&it))            {                gchar * pl;                gtk_tree_model_get(GTK_TREE_MODEL(pluginList),&it,PluginName,&pl,-1);                if (strcmp(pl,o->value.l[i].s)==0 || strcmp(pl,"_")==0) // yeah sets it more than once, I know                    gtk_list_store_set(pluginList,&it,PluginEnabled,TRUE,-1);                if (strcmp(pl,"_")==0)                    gtk_list_store_set(pluginList,&it,PluginCanEnable,FALSE,-1);                g_free(pl);            }        }    }}void do_active_plugins(){    g_slist_foreach(SETOptions,(GFunc)doing_active_plugins,NULL);}void cb_showpage(GtkWidget * w, GtkWidget * p){    gint i;    GtkTreeIter it;    GtkTreeSelection * Select;    Select=GTK_TREE_SELECTION(w);    GtkTreeModel * mod;    gchar * nam;    if (gtk_bin_get_child(GTK_BIN(p)))    {        gtk_container_remove(GTK_CONTAINER(p),gtk_bin_get_child(GTK_BIN(p)));    }    if (gtk_tree_selection_get_selected(Select,&mod,&it))    {        gtk_tree_model_get(mod,&it,PluginName,&nam,-1);    }    else        return;    if (!nam)        return;    for (i=0;i<nPages;i++)    {        if (strcmp(SETOptionPages[i].name,nam)==0)        {            gtk_container_add(GTK_CONTAINER(p),SETOptionPages[i].widget);            gtk_widget_show_all(SETOptionPages[i].widget);            return;        }    }    g_free(nam);}void beryl_settings_deactivate_plugin(gchar * plugin);void beryl_settings_activate_plugin(gchar * plugin);void beryl_settings_deactivate_plugin(gchar * plugin){    gint i;    for (i=0;i<nPages;i++)    {        gchar ** rq;        gsize nrq;        gint j;        if (strcmp(SETOptionPages[i].name,"_")==0)            continue;        rq=g_key_file_get_string_list(schemaFile,SETOptionPages[i].name,"d_p_requires",&nrq,NULL);        if (!rq)            g_error("plugin %s has no d_p_requires",SETOptionPages[i].name);        for (j=0;j<nrq;j++)        {            if (strcmp(rq[j],plugin)==0)                beryl_settings_deactivate_plugin(SETOptionPages[i].name);        }        g_strfreev(rq);    }    set_plugin_active(plugin,FALSE);}void beryl_settings_activate_plugin(gchar * plugin){    //activate all the plugin's deps    gchar ** rq;    gsize nrq;    gint i;    if (strcmp(plugin,"dbus")==0)        return;    rq=g_key_file_get_string_list(schemaFile,plugin,"d_p_requires",&nrq,NULL);    if (!rq)        g_error("plugin %s has no d_p_requires",plugin);    for (i=0;i<nrq;i++)        beryl_settings_activate_plugin(rq[i]);    g_strfreev(rq);    set_plugin_active(plugin,TRUE);}void do_unlisted_plugins(){    gchar ** alist;    gsize lal=0;    gint i,j;    gint sothers;    alist=g_key_file_get_string_list(schemaFile,"_","h_a_active_plugins",&lal,NULL);    if (!alist)        g_error("can't find d_a_active_plugins");    //nPages should be = lal+others-2+1    //so, others=nPages-lal+2-1    //=nPages-lal+1    nOthers=nPages-lal+1;    oplugs=malloc(sizeof(gchar *)*nOthers);    sothers=0;    for (i=0;i<nPages;i++)    {        gboolean found=FALSE;        if (strcmp(SETOptionPages[i].name,"_")==0)            continue;        for(j=0;j<lal;j++)        {            if (strcmp(alist[j],SETOptionPages[i].name)==0)                found=TRUE;        }        if (!found)            oplugs[sothers++]=SETOptionPages[i].name;    }    g_strfreev(alist);}void cb_toggled(GtkCellRendererToggle * t, gchar * path, gpointer d){    GtkTreeIter it;    gboolean b;    gchar * pn;    gsize lal;    gint i;    gchar ** alist;    gchar ** blist; // append any plugins like bench to make this list    GtkTreePath * p = gtk_tree_path_new_from_string(path);    if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(pluginList),&it,p))        g_error("invalid toggle");    gtk_tree_path_free(p);    gtk_tree_model_get(GTK_TREE_MODEL(pluginList),&it,PluginEnabled,&b,PluginName,&pn,-1);    if (b)        beryl_settings_deactivate_plugin(pn);    else        beryl_settings_activate_plugin(pn);    g_free(pn);    alist=g_key_file_get_string_list(schemaFile,"_","h_a_active_plugins",&lal,NULL);    if (!alist)        g_error("can't find d_a_active_plugins");    blist=malloc(sizeof(gchar*)*(lal+nOthers));    memcpy(blist,alist,sizeof(gchar *)*lal);    blist[lal+nOthers-1]=blist[lal-1]; // move bench to the end    for (i=0;i<nOthers;i++)    {        blist[i+lal-1]=oplugs[i];    }    lal+=nOthers;    for (i=0;i<lal;i++)    {        if (!get_plugin_active(blist[i]))        {            memmove(blist+i,blist+(i+1),sizeof(gchar *)*(lal-i-1));            i--;            lal--;        }    }    g_key_file_set_string_list(settingsFile,"_","a_active_plugins",(const gchar **)blist,lal);    pn=g_strconcat(g_get_home_dir(),"/.beryl/settings",NULL);    g_file_set_contents(pn,g_key_file_to_data(settingsFile,NULL,NULL),-1,NULL);    free(blist);    g_strfreev(alist);    send_option_changed_signal("_","a_active_plugins");}void cb_main_destroy(GtkWidget * w, gpointer p){    gtk_main_quit();}void layout_main_window(){    GType SETPluginListTypes[]=    {        G_TYPE_STRING,        G_TYPE_STRING,        G_TYPE_STRING,        G_TYPE_STRING,        GDK_TYPE_PIXBUF,        G_TYPE_BOOLEAN,        G_TYPE_BOOLEAN,    };    GtkBox * box;    GtkBox * ebox;    GtkBox * bbox;    GtkTreeViewColumn * col;    GtkScrolledWindow * win;    gchar ** groups;    gint page;    GtkCellRenderer * rend;    gsize nGroups=0;    gint i;    ebox = GTK_BOX(gtk_vbox_new(FALSE,2));    box = GTK_BOX(gtk_hbox_new(FALSE,2));    gtk_box_pack_start(ebox,GTK_WIDGET(box),TRUE,TRUE,0);    gtk_container_add(GTK_CONTAINER(mainWindow),GTK_WIDGET(ebox));    win = GTK_SCROLLED_WINDOW(gtk_scrolled_window_new(NULL,NULL));    gtk_scrolled_window_set_policy(win,GTK_POLICY_NEVER,GTK_POLICY_AUTOMATIC);    pluginList = gtk_list_store_newv(PluginEntryCount,SETPluginListTypes);    SETPluginList = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(pluginList)));    gtk_container_add(GTK_CONTAINER(win),GTK_WIDGET(SETPluginList));    gtk_tree_view_set_headers_visible(SETPluginList,FALSE);    gtk_tree_view_set_rules_hint(SETPluginList,TRUE);    rend = gtk_cell_renderer_pixbuf_new();    col = gtk_tree_view_column_new_with_attributes("Icon",rend,"pixbuf",PluginIcon,NULL);    gtk_tree_view_append_column(SETPluginList,col);    rend = gtk_cell_renderer_text_new();    g_object_set(G_OBJECT(rend),"wrap-mode",PANGO_WRAP_WORD,"wrap-width",160,NULL);    col = gtk_tree_view_column_new_with_attributes("Name",rend,            "markup",Markup,NULL);    gtk_tree_view_append_column(SETPluginList,col);    rend = gtk_cell_renderer_toggle_new();    //g_object_set(rend,"mode",GTK_CELL_RENDERER_MODE_EDITABLE,NULL);    col = gtk_tree_view_column_new_with_attributes("Active",rend,"activatable",PluginCanEnable,            "active",PluginEnabled,NULL);    gtk_tree_view_append_column(SETPluginList,col);    groups=g_key_file_get_groups(schemaFile,&nGroups);    SETOptionPages = malloc(sizeof(SETPage)*nGroups-1); // dbus hack    nPages=nGroups-1;    page=0;    for(i=0;i<nGroups;i++)    {        GtkTreeIter t;        gchar * shortdesc;        gchar * longdesc;        gchar * mark;        if (strcmp(groups[i],"dbus")==0)            continue;        GdkPixbuf * p;        p = gdk_pixbuf_new_from_file(g_strconcat(PIXMAPS_DIR,"/beryl-settings-section-",groups[i],".png",NULL),NULL);        if (!p)        {            gint w,h;            gtk_icon_size_lookup(GTK_ICON_SIZE_LARGE_TOOLBAR,&w,&h);            p = gdk_pixbuf_new_from_file_at_size(g_strconcat(PIXMAPS_DIR,"/beryl-settings-section-",groups[i],".svg",NULL),                    w,h,NULL);            if (!p)                p = gdk_pixbuf_new_from_file_at_size(DATADIR "/beryl/icon.png",w,h,NULL);        }        //    p = gtk_widget_render_icon(GTK_WIDGET(SETPluginList),GTK_STOCK_MISSING_IMAGE,        //            GTK_ICON_SIZE_LARGE_TOOLBAR,"berylplugin");        //look up short & long desc in file        //if its 'general', provide defaults        shortdesc = g_key_file_get_string(schemaFile,groups[i],"n_p_info",NULL);        if (!shortdesc)            shortdesc = g_strdup(_("General Options"));        longdesc = g_key_file_get_string(schemaFile,groups[i],"l_p_info",NULL);        if (!longdesc)            longdesc = g_strdup(_("Options for Beryl as a whole"));        gtk_list_store_append(pluginList,&t);        mark = g_markup_printf_escaped(                "<b>%s</b>\n"                "<small>[%s] <i>%s</i></small>"                ,shortdesc,groups[i],longdesc);        gtk_list_store_set(pluginList,&t,PluginName,groups[i],ShortDesc,shortdesc,                LongDesc,longdesc,Markup,mark,PluginIcon,p,PluginEnabled,FALSE,PluginCanEnable,TRUE,-1);        g_free(mark);        g_free(shortdesc);        g_free(longdesc);        SETOptionPages[page].name=g_strdup(groups[i]);        SETOptionPages[page].widget=gtk_notebook_new();        g_object_ref(SETOptionPages[page].widget);        do_option_page(groups[i],SETOptionPages[page].widget);        page++;    }    g_strfreev(groups);    do_unlisted_plugins();    gtk_box_pack_start(box,GTK_WIDGET(win),FALSE,FALSE,0);    gtk_box_pack_start(box,gtk_vseparator_new(),FALSE,FALSE,0);    pluginContainer = gtk_alignment_new(0,0,1,1);    gtk_container_add(GTK_CONTAINER(pluginContainer),SETOptionPages[0].widget);    {        GtkWidget * vbox, *hbox;        GtkWidget * but;        GtkWidget * win;        vbox = gtk_vbox_new(FALSE,2);        gtk_box_pack_start(GTK_BOX(vbox),GTK_WIDGET(pluginContainer),TRUE,TRUE,0);        infoLabel=gtk_label_new("");        hbox = gtk_hbox_new(FALSE,2);        infoContainer=hbox;        g_object_ref(hbox);        gtk_box_pack_start(GTK_BOX(vbox),hbox,FALSE,FALSE,0);        but=gtk_button_new_with_label(_("Hide"));        gtk_button_set_image(GTK_BUTTON(but),                gtk_image_new_from_stock(GTK_STOCK_CLOSE,GTK_ICON_SIZE_BUTTON));        g_signal_connect(but,"clicked",G_CALLBACK(set_info_pane),"");        win = gtk_scrolled_window_new(NULL,NULL);        gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(win),infoLabel);        gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(win),                GTK_POLICY_AUTOMATIC,GTK_POLICY_NEVER);        gtk_box_pack_start(GTK_BOX(hbox),but,FALSE,FALSE,0);        gtk_box_pack_start(GTK_BOX(hbox),win,TRUE,TRUE,0);        gtk_box_pack_start(box,GTK_WIDGET(vbox),TRUE,TRUE,0);        gtk_misc_set_alignment(GTK_MISC(infoLabel),0,0);        gtk_label_set_line_wrap(GTK_LABEL(infoLabel),TRUE);        //gtk_widget_set_size_request(GTK_LABEL(infoLabel),200,-1);        //gtk_label_set_max_width_chars(GTK_LABEL(infoLabel),50);    }    do_active_plugins();    g_signal_connect(rend,"toggled",G_CALLBACK(cb_toggled),NULL);    g_signal_connect(gtk_tree_view_get_selection(SETPluginList),"changed",            G_CALLBACK(cb_showpage),pluginContainer);    gtk_box_pack_start(ebox,gtk_hseparator_new(),FALSE,FALSE,0);    bbox=GTK_BOX(gtk_hbox_new(FALSE,0));    gtk_box_pack_start(ebox,GTK_WIDGET(bbox),FALSE,FALSE,0);    {        GtkWidget * quitbutton;        quitbutton=gtk_button_new_from_stock(GTK_STOCK_QUIT);        gtk_box_pack_end(bbox,quitbutton,FALSE,FALSE,0);        g_signal_connect(quitbutton,"clicked",G_CALLBACK(cb_main_destroy),NULL);    }}void setup_main_window(){    mainWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);    gtk_window_set_title(GTK_WINDOW(mainWindow),"Beryl Settings Manager " VERSION);    gtk_window_set_resizable(GTK_WINDOW(mainWindow),TRUE);    //gtk_window_set_position(GTK_WINDOW(mainWindow),GTK_WIN_POS_CENTER);    gtk_window_set_default_size(GTK_WINDOW(mainWindow),780,500);    gtk_window_set_default_icon_from_file(PIXMAPS_DIR "/beryl-settings.svg",NULL);    gtk_container_set_border_width(GTK_CONTAINER(mainWindow),5);    layout_main_window();    g_signal_connect(G_OBJECT (mainWindow), "destroy", G_CALLBACK(cb_main_destroy), NULL);    gtk_widget_show_all(mainWindow);    gtk_widget_hide(infoContainer);    g_timeout_add(1000,dequeue_sig,NULL);}int main(int argc, char ** argv){    gtk_init(&argc,&argv);    gchar * smmser;    //set the locale stuff    setlocale(LC_ALL,"");    bindtextdomain("beryl-settings","/usr/share/locale");    textdomain("beryl-settings");    //end locale    smmser=g_strconcat(g_get_home_dir(),"/.beryl",NULL);    g_mkdir_with_parents(smmser,00755);    g_chmod(smmser,00755);    g_free(smmser);    if (!g_thread_supported()) g_thread_init(NULL);    dbus_g_thread_init();    dbcon = dbus_bus_get (DBUS_BUS_SESSION,NULL);    if (!dbcon)        g_error("couldn't get dbus.");    dbus_connection_setup_with_g_main(dbcon,NULL); //    send_option_changed_signal("_","active_plugins");    load_schema_files();    setup_main_window();    gtk_main();    return 0;}