/*
 *  KDE libccs backend
 *
 *  Copyright (c) 2006 Dennis Kasprzyk <onestone@opencompositing.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.
 *
 *  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.
 *
 */

#include <tqdir.h>

#include <tdeconfig.h>
#include <ksimpleconfig.h>
#include <kdebug.h>
#include <tdeglobal.h>
#include <kstandarddirs.h>
#include <kinstance.h>
#include <tdeshortcut.h>
#include <kipc.h>
#include <tdeapplication.h>
#include <dcopclient.h>
#include <kdirwatch.h>
#include <stdlib.h>
#include <X11/X.h>
#include <X11/Xlib.h>

extern "C"
{
#include <ccs.h>
#include <ccs-backend.h>
}

#define CORE_NAME "core"

#define CompAltMask        (1 << 16)
#define CompMetaMask       (1 << 17)
#define CompSuperMask      (1 << 18)
#define CompHyperMask      (1 << 19)
#define CompModeSwitchMask (1 << 20)
#define CompNumLockMask    (1 << 21)
#define CompScrollLockMask (1 << 22)

static TDEInstance *instance = NULL;

typedef struct _ConfigFiles
{
    KSimpleConfig *main;
    TQString       profile;
    TDEConfig       *twin;
    TDEConfig       *global;
    Bool          modified;
    unsigned int  watch;
    unsigned int  twinWatch;
    unsigned int  globalWatch;
}

ConfigFiles;

static ConfigFiles *cFiles = NULL;

typedef enum
{
    OptionInt,
    OptionBool,
    OptionKey,
    OptionSpecial
}

SpecialOptionType;

struct _SpecialOption
{
    TQString           settingName;
    TQString           pluginName;
    TQString           kdeName;
    bool              global;
    SpecialOptionType type;
}

const specialOptions[] =
{
    {"close_window_key", CORE_NAME, "Window Close", true, OptionKey},
    {"lower_window_key", CORE_NAME, "Window Lower", true, OptionKey},
    {"toggle_window_maximized_key", CORE_NAME, "Window Maximize", true, OptionKey},
    {"minimize_window_key", CORE_NAME, "Window Minimize", true, OptionKey},
    {"toggle_window_maximized_horizontally_key", CORE_NAME, "Window Maximize Horizontal", true, OptionKey},
    {"toggle_window_maximized_vertically_key", CORE_NAME, "Window Maximize Vertical", true, OptionKey},
    {"show_desktop_key", CORE_NAME, "Toggle Showing Desktop", true, OptionKey},
    {"window_menu_key", CORE_NAME, "Window Operations Menu", true, OptionKey},
    {"toggle_window_shaded_key", CORE_NAME, "Window Shade", true, OptionKey},
    {"raise_window_key", CORE_NAME, "Window Raise", true, OptionKey},
    {"toggle_window_fullscreen_key", CORE_NAME, "Window Fullscreen", true, OptionKey},
    {"run_command11_key", "commands", "Kill Window", true, OptionKey},
    {"initiate_key", "move", "Window Move", true, OptionKey},
    {"initiate_key", "resize", "Window Resize", true, OptionKey},
    {"rotate_right_key", "rotate", "Switch to Next Desktop", true, OptionKey},
    {"rotate_left_key", "rotate", "Switch to Previous Desktop", true, OptionKey},
    {"rotate_to_1_key", "rotate", "Switch to Desktop 1", true, OptionKey},
    {"rotate_to_2_key", "rotate", "Switch to Desktop 2", true, OptionKey},
    {"rotate_to_3_key", "rotate", "Switch to Desktop 3", true, OptionKey},
    {"rotate_to_4_key", "rotate", "Switch to Desktop 4", true, OptionKey},
    {"rotate_to_5_key", "rotate", "Switch to Desktop 5", true, OptionKey},
    {"rotate_to_6_key", "rotate", "Switch to Desktop 6", true, OptionKey},
    {"rotate_to_7_key", "rotate", "Switch to Desktop 7", true, OptionKey},
    {"rotate_to_8_key", "rotate", "Switch to Desktop 8", true, OptionKey},
    {"rotate_to_9_key", "rotate", "Switch to Desktop 9", true, OptionKey},
    {"rotate_to_10_key", "rotate", "Switch to Desktop 10", true, OptionKey},
    {"rotate_to_11_key", "rotate", "Switch to Desktop 11", true, OptionKey},
    {"rotate_to_12_key", "rotate", "Switch to Desktop 12", true, OptionKey},
    {"rotate_right_window_key", "rotate", "Window to Next Desktop", true, OptionKey},
    {"rotate_left_window_key", "rotate", "Window to Previous Desktop", true, OptionKey},
    {"rotate_to_1_window_key", "rotate", "Window to Desktop 1", true, OptionKey},
    {"rotate_to_2_window_key", "rotate", "Window to Desktop 2", true, OptionKey},
    {"rotate_to_3_window_key", "rotate", "Window to Desktop 3", true, OptionKey},
    {"rotate_to_4_window_key", "rotate", "Window to Desktop 4", true, OptionKey},
    {"rotate_to_5_window_key", "rotate", "Window to Desktop 5", true, OptionKey},
    {"rotate_to_6_window_key", "rotate", "Window to Desktop 6", true, OptionKey},
    {"rotate_to_7_window_key", "rotate", "Window to Desktop 7", true, OptionKey},
    {"rotate_to_8_window_key", "rotate", "Window to Desktop 8", true, OptionKey},
    {"rotate_to_9_window_key", "rotate", "Window to Desktop 9", true, OptionKey},
    {"rotate_to_10_window_key", "rotate", "Window to Desktop 10", true, OptionKey},
    {"rotate_to_11_window_key", "rotate", "Window to Desktop 11", true, OptionKey},
    {"rotate_to_12_window_key", "rotate", "Window to Desktop 12", true, OptionKey},

    {"next_key", "wall", "Switch to Next Desktop", true, OptionKey},
    {"prev_key", "wall", "Switch to Previous Desktop", true, OptionKey},
    {"right_window_key", "wall", "Window One Desktop to the Right", true, OptionKey},
    {"left_window_key", "wall", "Window One Desktop to the Left", true, OptionKey},
    {"up_window_key", "wall", "Window One Desktop Up", true, OptionKey},
    {"down_window_key", "wall", "Window One Desktop Down", true, OptionKey},
    {"up_key", "wall", "Switch One Desktop Up", true, OptionKey},
    {"down_key", "wall", "Switch One Desktop Down", true, OptionKey},
    {"left_key", "wall", "Switch One Desktop to the Left", true, OptionKey},
    {"right_key", "wall", "Switch One Desktop to the Right", true, OptionKey},

    {"switch_to_1_key", "vpswitch", "Switch to Desktop 1", true, OptionKey},
    {"switch_to_2_key", "vpswitch", "Switch to Desktop 2", true, OptionKey},
    {"switch_to_3_key", "vpswitch", "Switch to Desktop 3", true, OptionKey},
    {"switch_to_4_key", "vpswitch", "Switch to Desktop 4", true, OptionKey},
    {"switch_to_5_key", "vpswitch", "Switch to Desktop 5", true, OptionKey},
    {"switch_to_6_key", "vpswitch", "Switch to Desktop 6", true, OptionKey},
    {"switch_to_7_key", "vpswitch", "Switch to Desktop 7", true, OptionKey},
    {"switch_to_8_key", "vpswitch", "Switch to Desktop 8", true, OptionKey},
    {"switch_to_9_key", "vpswitch", "Switch to Desktop 9", true, OptionKey},
    {"switch_to_10_key", "vpswitch", "Switch to Desktop 10", true, OptionKey},
    {"switch_to_11_key", "vpswitch", "Switch to Desktop 11", true, OptionKey},
    {"switch_to_12_key", "vpswitch", "Switch to Desktop 12", true, OptionKey},

    {"autoraise", CORE_NAME, "AutoRaise", false, OptionBool},
    {"raise_on_click", CORE_NAME, "ClickRaise", false, OptionBool},
    {"snapoff_maximized", "move", "MoveResizeMaximizedWindows", false, OptionBool},
    {"always_show", "resizeinfo", "GeometryTip", false, OptionBool},
    {"allow_wraparound", "wall", "RollOverDesktops",  false, OptionBool},

    {"autoraise_delay", CORE_NAME, "AutoRaiseInterval", false, OptionInt},
    {"flip_time", "rotate", "ElectricBorderDelay", false, OptionInt},

    {"unmaximize_window_key", CORE_NAME, NULL, true, OptionSpecial},
    {"maximize_window_key", CORE_NAME, NULL, true, OptionSpecial},
    {"maximize_window_horizontally_key", CORE_NAME, NULL, true, OptionSpecial},
    {"maximize_window_vertically_key", CORE_NAME, NULL, true, OptionSpecial},
    {"command11", "commands", NULL, true, OptionSpecial},
    {"click_to_focus", CORE_NAME, NULL, false, OptionSpecial},
    {"mode", "resize", NULL, true, OptionSpecial},
    {"number_of_desktops", CORE_NAME, "Number", false, OptionSpecial},

    {"snap_type", "snap", NULL, false, OptionSpecial},
    {"edges_categories", "snap", NULL, false, OptionSpecial},
    {"resistance_distance", "snap", NULL, false, OptionSpecial},
    {"attraction_distance", "snap", NULL, false, OptionSpecial},

    {"next_key", "switcher", "Walk Through Windows", true, OptionSpecial},
    {"prev_key", "switcher", "Walk Through Windows (Reverse)", true, OptionSpecial},
    {"next_all_key", "switcher", "Walk Through Windows", true, OptionSpecial},
    {"prev_all_key", "switcher", "Walk Through Windows (Reverse)", true, OptionSpecial},
    {"next_no_popup_key", "switcher", "Walk Through Windows", true, OptionSpecial},
    {"prev_no_popup_key", "switcher", "Walk Through Windows (Reverse)", true, OptionSpecial},

    {"edge_flip_pointer", "rotate", "ElectricBorders",  false, OptionSpecial},
    {"edge_flip_window", "rotate", "ElectricBorders",  false, OptionSpecial},
    {"edgeflip_pointer", "wall", "ElectricBorders",  false, OptionSpecial},
    {"edgeflip_move", "wall", "ElectricBorders",  false, OptionSpecial},

    {"mode", "place", "Placement",  false, OptionSpecial}
};

#define N_SOPTIONS (sizeof (specialOptions) / sizeof (struct _SpecialOption))

static void
createFile (TQString name)
{
    if (!TQFile::exists(name))
    {
	TQFile file (name);
	file.open (IO_WriteOnly | IO_Append);
	file.close ();
    }
}

static void
reload (unsigned int,
	void     *closure)
{
    CCSContext *context = (CCSContext *) closure;

    ccsDisableFileWatch (cFiles->watch);
    ccsDisableFileWatch (cFiles->twinWatch);
    ccsDisableFileWatch (cFiles->globalWatch);
    cFiles->main->reparseConfiguration();
    cFiles->twin->reparseConfiguration();
    cFiles->global->reparseConfiguration();
    ccsReadSettings (context);
    ccsEnableFileWatch (cFiles->watch);
    ccsEnableFileWatch (cFiles->twinWatch);
    ccsEnableFileWatch (cFiles->globalWatch);
}

static bool
isIntegratedOption (CCSSetting *setting)
{

    for (unsigned int i = 0; i < N_SOPTIONS; i++)
    {
	if (setting->name == specialOptions[i].settingName &&
	    TQString (setting->parent->name) == specialOptions[i].pluginName)
	    return true;
    }

    return false;
}

static void
KdeIntToCCS (CCSSetting *setting,
	     int        num)
{
    TDEConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->twin;

    int val = cfg->readNumEntry (specialOptions[num].kdeName);

    ccsSetInt (setting, val);
}

static void
KdeBoolToCCS (CCSSetting *setting,
	      int        num)
{
    TDEConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->twin;

    Bool val = (cfg->readBoolEntry (specialOptions[num].kdeName))? TRUE : FALSE;

    ccsSetBool (setting, val);
}

static void
KdeKeyToCCS (CCSSetting *setting,
	     int        num)
{
    TDEConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->twin;

    KKey key (cfg->readEntry (specialOptions[num].kdeName) );

    int kdeKeysym = key.sym();
    int kdeKeymod = 0;

    if (key.modFlags() & KKey::SHIFT)
	kdeKeymod |= ShiftMask;

    if (key.modFlags() & KKey::CTRL)
	kdeKeymod |= ControlMask;

    if (key.modFlags() & KKey::ALT)
	kdeKeymod |= CompAltMask;

    if (key.modFlags() & KKey::WIN)
	kdeKeymod |= CompSuperMask;

    CCSSettingKeyValue keySet;

    if (!key.isNull())
    {
	keySet.keysym = kdeKeysym;
	keySet.keyModMask = kdeKeymod;
	ccsSetKey (setting, keySet);
    }
}


static void
readIntegratedOption (CCSSetting *setting)
{
    int option = 0;

    for (unsigned int i = 0; i < N_SOPTIONS; i++)
    {
	if (setting->name == specialOptions[i].settingName &&
	    TQString (setting->parent->name) == specialOptions[i].pluginName)
	{
	    option = i;
	    break;
	}
    }

    switch (specialOptions[option].type)
    {

    case OptionInt:
	KdeIntToCCS (setting, option);
	break;

    case OptionBool:
	KdeBoolToCCS (setting, option);
	break;

    case OptionKey:
	KdeKeyToCCS (setting, option);
	break;

    case OptionSpecial:
	if (specialOptions[option].settingName == "command11")
	{
	    ccsSetString (setting, "xkill");
	}
	else if (specialOptions[option].settingName == "unmaximize_window_key"
		 || specialOptions[option].settingName == "maximize_window_key"
		 || specialOptions[option].settingName == "maximize_window_horizontally_key"
		 || specialOptions[option].settingName == "maximize_window_vertically_key")
	{
	    CCSSettingKeyValue keyVal;

	    if (!ccsGetKey (setting, &keyVal) )
		break;

	    keyVal.keysym = 0;

	    keyVal.keyModMask = 0;

	    ccsSetKey (setting, keyVal);
	}
	else if (specialOptions[option].settingName == "click_to_focus")
	{
	    Bool val = (cFiles->twin->readEntry ("FocusPolicy") ==
			    "ClickToFocus") ? TRUE : FALSE;
	    ccsSetBool (setting, val);
	}
	else if (specialOptions[option].settingName == "number_of_desktops")
	{
	    cFiles->twin->setGroup ("Desktops");
	    KdeIntToCCS (setting, option);
	    cFiles->twin->setGroup ("Windows");
	}
	else if (specialOptions[option].settingName == "mode" &&
		 specialOptions[option].pluginName == "resize")
	{
	    TQString mode = cFiles->twin->readEntry ("ResizeMode");
	    int     imode = -1;
	    int     result = 0;

	    if (cFiles->main->hasKey (specialOptions[option].settingName +
		       		      " (Integrated)") )
		imode = cFiles->main->readNumEntry (
			specialOptions[option].settingName + " (Integrated)");

	    if (mode == "Opaque")
	    {
		result = 0;

		if (imode == 3)
		    result = 3;
	    }
	    else if (mode == "Transparent")
	    {
		result = 1;

		if (imode == 2)
		    result = 2;
	    }

	    ccsSetInt (setting, result);
	}
	else if (specialOptions[option].settingName == "snap_type")
	{
	    static int intList[2] = {0, 1};
	    CCSSettingValueList list = ccsGetValueListFromIntArray (intList, 2,
								    setting);
	    ccsSetList (setting, list);
	    ccsSettingValueListFree (list, TRUE);
	}
	else if (specialOptions[option].settingName == "resistance_distance" ||
		 specialOptions[option].settingName == "attraction_distance")
	{
	    int val1 = cFiles->twin->readNumEntry ("WindowSnapZone");
	    int val2 = cFiles->twin->readNumEntry ("BorderSnapZone");
	    int result = KMAX (val1, val2);

	    if (result == 0)
		result =  cFiles->main->readNumEntry ("snap_distance (Integrated)");

	    if (result > 0)
	    	ccsSetInt (setting, result);
	}
	else if (specialOptions[option].settingName == "edges_categories")
	{
	    int val1 = cFiles->twin->readNumEntry ("WindowSnapZone");
	    int val2 = cFiles->twin->readNumEntry ("BorderSnapZone");
	    int intList[2] = {0, 0};
	    int num = 0;

	    if (val2 > 0)
		num++;
	    if (val1 > 0)
	    {
		intList[num] = 1;
		num++;
	    }

	    CCSSettingValueList list = ccsGetValueListFromIntArray (intList,
								    num,
								    setting);
	    ccsSetList (setting, list);
	    ccsSettingValueListFree (list, TRUE);
	}
	else if (specialOptions[option].settingName == "next_key" ||
		 specialOptions[option].settingName == "prev_key")
	{
	    bool val1;
	    bool val2 = (cFiles->twin->readEntry ("AltTabStyle") == "KDE");

	    cFiles->twin->setGroup ("TabBox");
	    val1 = cFiles->twin->readBoolEntry ("TraverseAll");
	    cFiles->twin->setGroup ("Windows");

	    if (val2 && !val1)
	    	KdeKeyToCCS (setting, option);
	    else
	    {
		 CCSSettingKeyValue keyVal;

		if (ccsGetKey (setting, &keyVal) )
		{
		    keyVal.keysym = 0;
		    keyVal.keyModMask = 0;
		    ccsSetKey (setting, keyVal);
		}
	    }
	}
	else if (specialOptions[option].settingName == "next_all_key" ||
		 specialOptions[option].settingName == "prev_all_key")
	{
	    bool val1;
	    bool val2 = (cFiles->twin->readEntry ("AltTabStyle") == "KDE");

	    cFiles->twin->setGroup ("TabBox");
	    val1 = cFiles->twin->readBoolEntry ("TraverseAll");
	    cFiles->twin->setGroup ("Windows");

	    if (val2 && val1)
	    	KdeKeyToCCS (setting, option);
	    else
	    {
		 CCSSettingKeyValue keyVal;

		if (ccsGetKey (setting, &keyVal) )
		{
		    keyVal.keysym = 0;
		    keyVal.keyModMask = 0;
		    ccsSetKey (setting, keyVal);
		}
	    }
	}
	else if (specialOptions[option].settingName == "next_no_popup_key" ||
		 specialOptions[option].settingName == "prev_no_popup_key")
	{
	    bool val2 = (cFiles->twin->readEntry ("AltTabStyle") == "KDE");

	    if (!val2)
	    	KdeKeyToCCS (setting, option);
	    else
	    {
		 CCSSettingKeyValue keyVal;

		if (ccsGetKey (setting, &keyVal) )
		{
		    keyVal.keysym = 0;
		    keyVal.keyModMask = 0;
		    ccsSetKey (setting, keyVal);
		}
	    }
	}
	else if (specialOptions[option].settingName == "edge_flip_window" ||
		 specialOptions[option].settingName == "edgeflip_move")
	{
	    int val = cFiles->twin->readNumEntry ("ElectricBorders");

	    if (val > 0)
		ccsSetBool (setting, TRUE);
	    else
		ccsSetBool (setting, FALSE);
	}
	else if (specialOptions[option].settingName == "edge_flip_pointer" ||
		 specialOptions[option].settingName == "edgeflip_pointer")
	{
	    int val = cFiles->twin->readNumEntry ("ElectricBorders");

	    if (val > 1)
		ccsSetBool (setting, TRUE);
	    else
		ccsSetBool (setting, FALSE);
	}
	else if (specialOptions[option].settingName == "mode" &&
		 specialOptions[option].pluginName == "place")
	{
	    TQString mode = cFiles->twin->readEntry ("Placement");
	    int     result = 0;


	    if (mode == "Smart")
		result = 2;
	    else if (mode == "Maximizing")
		result = 3;
	    else if (mode == "Cascade")
		result = 0;
	    else if (mode == "Random")
		result = 4;
	    else if (mode == "Centered")
		result = 1;

	    ccsSetInt (setting, result);
	}
	break;

    default:
	break;
    }
}


static Bool
getSettingIsIntegrated (CCSSetting *setting)
{
    return ccsGetIntegrationEnabled (setting->parent->context)
	   && isIntegratedOption (setting);
}


static Bool
getSettingIsReadOnly (CCSSetting *setting)
{
    if (!ccsGetIntegrationEnabled (setting->parent->context)
	|| !isIntegratedOption (setting) )
	return FALSE;

    int option = 0;

    for (unsigned int i = 0; i < N_SOPTIONS; i++)
    {
	if (setting->name == specialOptions[i].settingName &&
	    TQString (setting->parent->name) == specialOptions[i].pluginName)
	{
	    option = i;
	    break;
	}
    }

    switch (specialOptions[option].type)
    {

    case OptionSpecial:
	if (specialOptions[option].settingName == "command11")
	{
	    return TRUE;
	}
	else if (specialOptions[option].settingName == "map_on_shutdown")
	{
	    return TRUE;
	}
	else if (specialOptions[option].settingName == "unmaximize_window_key"
		 || specialOptions[option].settingName == "maximize_window_key"
		 || specialOptions[option].settingName == "maximize_window_horizontally_key"
		 || specialOptions[option].settingName == "maximize_window_vertically_key")
	{
	    return TRUE;
	}
	else if (specialOptions[option].settingName == "snap_type" ||
		 specialOptions[option].settingName == "attraction_distance")
	{
	    return TRUE;
	}
	break;

    default:
	break;
    }

    return FALSE;
}

static CCSStringList
getExistingProfiles (CCSContext *)
{
    if (!instance)
	instance = new TDEInstance ("ccs-backend-tdeconfig");

    TQDir dir (TDEGlobal::dirs()->saveLocation ("config", TQString(), false),
	      				     "compizrc.*");

    TQStringList files = dir.entryList();
    CCSStringList ret = NULL;

    TQStringList::iterator it;

    for (it = files.begin(); it != files.end(); it++)
    {
	TQString str = (*it);

	if (str.length() > 9)
	{
	    TQString profile = str.right (str.length() - 9);

	    if (!profile.isEmpty() )
		ret = ccsStringListAppend (ret, strdup (profile.ascii() ) );
	}
    }

    return ret;
}

static void
readSetting (CCSContext *c,
	     CCSSetting *setting)
{

    KSimpleConfig *cfg = cFiles->main;

    TQString key (setting->name);
    TQString group (setting->parent->name);

    if (setting->isScreen)
    {
	group += "_screen";
	group += TQString::number (setting->screenNum);
    }
    else
	group += "_display";

    cfg->setGroup (group);

    if (ccsGetIntegrationEnabled (c) && isIntegratedOption (setting) )
    {
	readIntegratedOption (setting);
	return;
    }


    if (!cfg->hasKey (key) )
    {
	ccsResetToDefault (setting);
	return;
    }

    switch (setting->type)
    {

    case TypeString:
	ccsSetString (setting, cfg->readEntry (key, "").ascii() );
	break;

    case TypeMatch:
	ccsSetMatch (setting, cfg->readEntry (key, "").ascii() );
	break;

    case TypeFloat:
	ccsSetFloat (setting, cfg->readDoubleNumEntry (key) );
	break;

    case TypeInt:
	ccsSetInt (setting, cfg->readNumEntry (key) );
	break;

    case TypeBool:
	{
	    Bool val = (cfg->readBoolEntry (key) ) ? TRUE : FALSE;
	    ccsSetBool (setting, val);
	}
	break;

    case TypeColor:
	{
	    TQString str = cfg->readEntry (key);
	    CCSSettingColorValue color;
	    int c[4];

	    if (sscanf (str.ascii (), "#%2x%2x%2x%2x",
			&c[0], &c[1], &c[2], &c[3]) == 4)
	    {
		color.color.red = c[0] << 8 | c[0];
		color.color.green = c[1] << 8 | c[1];
		color.color.blue = c[2] << 8 | c[2];
		color.color.alpha = c[3] << 8 | c[3];
	    }

	    ccsSetColor (setting, color);
	}
	break;

    case TypeList:
	{
	    switch (setting->info.forList.listType)
	    {

	    case TypeBool:
		{
		    TQValueList<int> list = cfg->readIntListEntry (key);

		    Bool *array = new Bool[list.count() ];
		    int i = 0;

		    TQValueList<int>::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			array[i] = ( (*it) ) ? TRUE : FALSE;
			i++;
		    }

		    CCSSettingValueList l =

			ccsGetValueListFromBoolArray (array, i, setting);
		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		    delete array;
		}
		break;

	    case TypeInt:
		{
		    TQValueList<int> list = cfg->readIntListEntry (key);

		    int *array = new int[list.count() ];
		    int i = 0;

		    TQValueList<int>::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			array[i] = (*it);
			i++;
		    }

		    CCSSettingValueList l =

			ccsGetValueListFromIntArray (array, i, setting);
		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		    delete array;
		}
		break;

	    case TypeString:
		{
		    TQStringList list = cfg->readListEntry (key);

		    if (!list.count() )
			break;

		    char **array = new char *[list.count() ];

		    int i = 0;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			array[i] = strdup ( (*it).ascii() );
			i++;
		    }

		    CCSSettingValueList l =

			ccsGetValueListFromStringArray (array, i, setting);
		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);

		    for (int j = 0; j < i; j++)
			free (array[j]);

		    delete [] array;

		}
		break;

	    case TypeMatch:
		{
		    TQStringList list = cfg->readListEntry (key);

		    if (!list.count() )
			break;

		    char **array = new char *[list.count() ];

		    int i = 0;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			array[i] = strdup ( (*it).ascii() );
			i++;
		    }

		    CCSSettingValueList l =

			ccsGetValueListFromStringArray (array, i, setting);
		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);

		    for (int j = 0; j < i; j++)
			free (array[j]);

		    delete [] array;

		}
		break;

	    case TypeFloat:
		{
		    TQStringList list = cfg->readListEntry (key);

		    float *array = new float[list.count() ];
		    int i = 0;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			array[i] = (*it).toDouble();
			i++;
		    }

		    CCSSettingValueList l =

			ccsGetValueListFromFloatArray (array, i, setting);
		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		    delete array;
		}
		break;

	    case TypeColor:
		{
		    TQStringList list = cfg->readListEntry (key);

		    CCSSettingColorValue *array =
			new CCSSettingColorValue[list.count() ];
		    int i = 0;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			int c[4];

			if (sscanf ((*it).ascii (), "#%2x%2x%2x%2x",
				    &c[0], &c[1], &c[2], &c[3]) == 4)
			{
			    array[i].color.red = c[0] << 8 | c[0];
			    array[i].color.green = c[1] << 8 | c[1];
			    array[i].color.blue = c[2] << 8 | c[2];
			    array[i].color.alpha = c[3] << 8 | c[3];
			}

			i++;
		    }

		    CCSSettingValueList l =

			ccsGetValueListFromColorArray (array, i, setting);
		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		    delete array;
		}
		break;

	    case TypeKey:
		{
		    TQStringList list = cfg->readListEntry (key);

		    CCSSettingValue     *val = NULL;
		    CCSSettingValueList l = NULL;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			val = (CCSSettingValue*) malloc (sizeof (CCSSettingValue));
			if (!val)
			    break;
			if (ccsStringToKeyBinding ((*it).ascii (),
			    			   &val->value.asKey))
			    l = ccsSettingValueListAppend (l, val);
			else
			    free (val);
		    }

		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		}
		break;
	    case TypeButton:
		{
		    TQStringList list = cfg->readListEntry (key);

		    CCSSettingValue     *val = NULL;
		    CCSSettingValueList l = NULL;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			val = (CCSSettingValue*) malloc (sizeof (CCSSettingValue));
			if (!val)
			    break;
			if (ccsStringToButtonBinding ((*it).ascii (),
			    			      &val->value.asButton))
			    l = ccsSettingValueListAppend (l, val);
			else
			    free (val);
		    }

		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		}
		break;
	    case TypeEdge:
		{
		    TQStringList list = cfg->readListEntry (key);

		    CCSSettingValue     *val = NULL;
		    CCSSettingValueList l = NULL;

		    TQStringList::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			val = (CCSSettingValue*) malloc (sizeof (CCSSettingValue));
			if (!val)
			    break;
			val->value.asEdge = ccsStringToEdges ((*it).ascii ());
			l = ccsSettingValueListAppend (l, val);
		    }

		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		}
		break;
	    case TypeBell:
		{
		    TQValueList<int> list = cfg->readIntListEntry (key);

		    CCSSettingValue     *val = NULL;
		    CCSSettingValueList l = NULL;

		    TQValueList<int>::iterator it;

		    for (it = list.begin(); it != list.end(); it++)
		    {
			val =  (CCSSettingValue*) malloc (sizeof (CCSSettingValue));
			val->value.asBell = ((*it)) ? TRUE : FALSE;
			l = ccsSettingValueListAppend (l, val);
		    }

		    ccsSetList (setting, l);
		    ccsSettingValueListFree (l, TRUE);
		}
		break;

	    default:
		break;
	    }
	}
	break;

    case TypeKey:
	{
	    TQString str = cfg->readEntry (key);

	    CCSSettingKeyValue value;

	    ccsStringToKeyBinding (str.ascii(), &value);

	    ccsSetKey (setting, value);
	}
	break;
    case TypeButton:
	{
	    TQString str = cfg->readEntry (key);

	    CCSSettingButtonValue value;

	    ccsStringToButtonBinding (str.ascii(), &value);

	    ccsSetButton (setting, value);
	}
	break;
    case TypeEdge:
	{
	    TQString str = cfg->readEntry (key);

	    unsigned int value;

	    value = ccsStringToEdges (str.ascii());

	    ccsSetEdge (setting, value);
	}
	break;
    case TypeBell:
	{
	    Bool val = (cfg->readBoolEntry (key)) ? TRUE : FALSE;
	    ccsSetBell (setting, val);
	}
	break;

    default:
	kdDebug () << "Not supported setting type : " << setting->type << endl;
	break;
    }
}

static void
CCSIntToKde (CCSSetting *setting,
	     int        num)
{
    TDEConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->twin;

    int val;

    if (!ccsGetInt (setting, &val) )
	return;

    if (cfg->readNumEntry (specialOptions[num].kdeName) != val)
    {
	cFiles->modified = true;
	cfg->writeEntry (specialOptions[num].kdeName, val);
    }
}

static void
CCSBoolToKde (CCSSetting *setting,
	      int        num)
{
    TDEConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->twin;

    Bool val;

    if (!ccsGetBool (setting, &val) )
	return;

    if (cfg->readBoolEntry (specialOptions[num].kdeName) != bool (val) )
    {
	cFiles->modified = true;
	cfg->writeEntry (specialOptions[num].kdeName, bool (val) );
    }
}

static void
CCSKeyToKde (CCSSetting *setting,
	     int        num)
{
    TDEConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->twin;

    CCSSettingKeyValue keyVal;

    if (!ccsGetKey (setting, &keyVal) )
	return;

    int kde_keymod = 0;

    if (keyVal.keyModMask & ShiftMask)
	kde_keymod |= KKey::SHIFT;

    if (keyVal.keyModMask & ControlMask)
	kde_keymod |= KKey::CTRL;

    if (keyVal.keyModMask & CompAltMask)
	kde_keymod |= KKey::ALT;

    if (keyVal.keyModMask & CompSuperMask)
	kde_keymod |= KKey::WIN;

    KKey key (keyVal.keysym, kde_keymod);

    KKey akey (cfg->readEntry (specialOptions[num].kdeName) );

    if (akey != key)
    {
	cFiles->modified = true;
	cfg->writeEntry (specialOptions[num].kdeName, key.toString() );
    }
}


static void
writeIntegratedOption (CCSSetting *setting)
{
    int option = 0;

    for (unsigned int i = 0; i < N_SOPTIONS; i++)
    {
	if (setting->name == specialOptions[i].settingName &&
	    TQString (setting->parent->name) == specialOptions[i].pluginName)
	{
	    option = i;
	    break;
	}
    }

    switch (specialOptions[option].type)
    {

    case OptionInt:
	CCSIntToKde (setting, option);
	break;

    case OptionBool:
	CCSBoolToKde (setting, option);
	break;

    case OptionKey:
	CCSKeyToKde (setting, option);
	break;

    case OptionSpecial:
	if (specialOptions[option].settingName == "command11"
	    || specialOptions[option].settingName == "unmaximize_window_key"
	    || specialOptions[option].settingName == "maximize_window_key"
	    || specialOptions[option].settingName == "maximize_window_horizontally_key"
	    || specialOptions[option].settingName == "maximize_window_vertically_key")
	    break;

	if (specialOptions[option].settingName == "click_to_focus")
	{
	    TQString mode = cFiles->twin->readEntry ("FocusPolicy");
	    TQString val = "ClickToFocus";
	    Bool bVal;

	    if (!ccsGetBool (setting, &bVal) )
		break;

	    if (!bVal)
	    {
		val = "FocusFollowsMouse";
	    }

	    if (mode != val)
	    {
		cFiles->modified = true;
		cFiles->twin->writeEntry ("FocusPolicy", val);
	    }
	}

	if (specialOptions[option].settingName == "number_of_desktops")
	{
	    cFiles->twin->setGroup ("Desktops");
	    CCSIntToKde (setting, option);
	    cFiles->twin->setGroup ("Windows");
	}
	if (specialOptions[option].settingName == "mode" &&
	    specialOptions[option].pluginName == "resize")
	{
		TQString mode = cFiles->twin->readEntry("ResizeMode");
		TQString val = "Opaque";
		int     iVal;
		if (ccsGetInt(setting, &iVal) && (iVal == 1 || iVal == 2))
		{
			val = "Transparent";
		}
		if (mode != val)
		{
			cFiles->modified = true;
			cFiles->twin->writeEntry("ResizeMode",val);
		}
		cFiles->main->writeEntry(specialOptions[option].settingName + " (Integrated)",iVal);
	}

	if (specialOptions[option].settingName == "resistance_distance" ||
	    specialOptions[option].settingName == "edges_categories")
	{
	    int *values, numValues;
	    CCSSettingValueList sList;

	    bool edge = false;
	    bool window = false;

	    int iVal = 0;

	    CCSSetting *edges = ccsFindSetting(setting->parent,
					       "edges_categories",
					       setting->isScreen,
					       setting->screenNum);

	    CCSSetting *dist = ccsFindSetting(setting->parent,
					      "resistance_distance",
					      setting->isScreen,
					      setting->screenNum);

	    if (!edges || !dist || !ccsGetList (edges, &sList) ||
		!ccsGetInt(dist, &iVal))
		break;

	    values = ccsGetIntArrayFromValueList (sList, &numValues);

	    for (int i = 0; i < numValues; i++)
	    {
		if (values[i] == 0)
		    edge = true;
		if (values[i] == 1)
		    window = true;
	    }

	    if (values)
		free (values);

	    if (edge)
		cFiles->twin->writeEntry ("BorderSnapZone", iVal);
	    else
		cFiles->twin->writeEntry ("BorderSnapZone", 0);

	    if (window)
		cFiles->twin->writeEntry ("WindowSnapZone", iVal);
	    else
		cFiles->twin->writeEntry ("WindowSnapZone", 0);
	    if (window | edge)
		cFiles->modified = true;
	    cFiles->main->writeEntry ("snap_distance (Integrated)",iVal);
	}
	else if (specialOptions[option].settingName == "next_key" ||
		 specialOptions[option].settingName == "prev_key")
	{
	    CCSSettingKeyValue keyVal;

	    if (!ccsGetKey (setting, &keyVal))
		break;

	    if (keyVal.keysym == 0 && keyVal.keyModMask == 0)
		break;

	    CCSKeyToKde (setting, option);

	    cFiles->twin->setGroup ("TabBox");
	    cFiles->twin->writeEntry ("TraverseAll", false);
	    cFiles->twin->setGroup ("Windows");

	    cFiles->twin->writeEntry ("AltTabStyle", "KDE");

	    cFiles->modified = true;
	}
	else if (specialOptions[option].settingName == "next_all_key" ||
		 specialOptions[option].settingName == "prev_all_key")
	{
	    CCSSettingKeyValue keyVal;

	    if (!ccsGetKey (setting, &keyVal))
		break;

	    if (keyVal.keysym == 0 && keyVal.keyModMask == 0)
		break;

	    CCSKeyToKde (setting, option);

	    cFiles->twin->setGroup ("TabBox");
	    cFiles->twin->writeEntry ("TraverseAll", true);
	    cFiles->twin->setGroup ("Windows");

	    cFiles->twin->writeEntry ("AltTabStyle", "KDE");

	    cFiles->modified = true;
	}
	else if (specialOptions[option].settingName == "next_no_popup_key" ||
		 specialOptions[option].settingName == "prev_no_popup_key")
	{
	    CCSSettingKeyValue keyVal;

	    if (!ccsGetKey (setting, &keyVal))
		break;

	    if (keyVal.keysym == 0 && keyVal.keyModMask == 0)
		break;

	    CCSKeyToKde (setting, option);

	    cFiles->twin->writeEntry ("AltTabStyle", "CDE");

	    cFiles->modified = true;
	}
	else if (specialOptions[option].settingName == "edge_flip_window" ||
		 specialOptions[option].settingName == "edgeflip_move")
	{
	    int  oVal = cFiles->twin->readNumEntry ("ElectricBorders");
	    Bool val;

	    if (!ccsGetBool (setting, &val))
		break;

	    if (val)
		cFiles->twin->writeEntry ("ElectricBorders", KMAX (1, oVal));
	    else
		cFiles->twin->writeEntry ("ElectricBorders", 0);
	    cFiles->modified = true;
	}
	else if (specialOptions[option].settingName == "edge_flip_pointer" ||
		 specialOptions[option].settingName == "edgeflip_pointer")
	{
	    int  oVal = 0;
	    Bool val, val2;

	    if (!ccsGetBool (setting, &val))
		break;


	    CCSSetting *valSet = ccsFindSetting(setting->parent,
						 "edge_flip_window",
						 setting->isScreen,
						 setting->screenNum);

	    if (!valSet)
	     	valSet = ccsFindSetting(setting->parent, "edgeflip_move",
					setting->isScreen, setting->screenNum);

	    if (valSet && ccsGetBool (valSet, &val2))
	    {
		if (val2)
		    oVal = 1;
	    }
	    else
		oVal = 0;


	    if (val)
		cFiles->twin->writeEntry ("ElectricBorders", 2);
	    else
		cFiles->twin->writeEntry ("ElectricBorders", oVal);
	    cFiles->modified = true;
	}
	else if (specialOptions[option].settingName == "mode" &&
		 specialOptions[option].pluginName == "place")
	{
	    int val;
	    if (!ccsGetInt (setting, &val))
		break;

	    switch (val)
	    {
	    case 0:
		cFiles->twin->writeEntry ("Placement", "Cascade");
		break;
	    case 1:
		cFiles->twin->writeEntry ("Placement", "Centered");
		break;
	    case 2:
		cFiles->twin->writeEntry ("Placement", "Smart");
		break;
	    case 3:
		cFiles->twin->writeEntry ("Placement", "Maximizing");
		break;
	    case 4:
		cFiles->twin->writeEntry ("Placement", "Random");
		break;
	    default:
		break;
	    }

	    cFiles->modified = true;
	}
	break;

    default:
	break;
    }
}


static void
writeSetting (CCSContext *c,
	      CCSSetting *setting)
{
    KSimpleConfig *cfg = cFiles->main;

    TQString key (setting->name);
    TQString group (setting->parent->name);

    if (setting->isScreen)
    {
	group += "_screen";
	group += TQString::number (setting->screenNum);
    }
    else
	group += "_display";

    cfg->setGroup (group);

    if (ccsGetIntegrationEnabled (c) && isIntegratedOption (setting) )
    {
	writeIntegratedOption (setting);
	return;
    }

    switch (setting->type)
    {

    case TypeString:
	{
	    char * val;

	    if (ccsGetString (setting, &val) )
		cfg->writeEntry (key, val);
	}
	break;

    case TypeMatch:
	{
	    char * val;

	    if (ccsGetMatch (setting, &val) )
		cfg->writeEntry (key, val);
	}
	break;

    case TypeFloat:
	{
	    float val;

	    if (ccsGetFloat (setting, &val) )
		cfg->writeEntry (key, val);
	}
	break;

    case TypeInt:
	{
	    int val;

	    if (ccsGetInt (setting, &val) )
		cfg->writeEntry (key, val);
	}
	break;

    case TypeBool:
	{
	    Bool val;

	    if (ccsGetBool (setting, &val) )
		cfg->writeEntry (key, bool (val) );
	}
	break;

    case TypeColor:
	{
	    CCSSettingColorValue color;
	    char tmp[256];

	    if (!ccsGetColor (setting, &color) )
		break;

	    snprintf (tmp, 256, "#%.2x%.2x%.2x%.2x",
		      color.color.red / 256,
		      color.color.green/ 256,
		      color.color.blue / 256,
		      color.color.alpha / 256);

	    cfg->writeEntry (key, TQString (tmp));
	}
	break;

    case TypeList:
	{
	    switch (setting->info.forList.listType)
	    {

	    case TypeBool:
		{
		    TQValueList<int> list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			list.append (l->data->value.asBool);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;

	    case TypeInt:
		{
		    TQValueList<int> list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			list.append (l->data->value.asInt);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;

	    case TypeString:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			list.append (l->data->value.asString);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;

	    case TypeMatch:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			list.append (l->data->value.asMatch);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;

	    case TypeFloat:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			list.append (TQString::number (l->data->value.asFloat) );
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;

	    case TypeColor:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			char tmp[256];

			snprintf (tmp, 256, "#%.2x%.2x%.2x%.2x",
				  l->data->value.asColor.array.array[0] / 256,
				  l->data->value.asColor.array.array[1] / 256,
				  l->data->value.asColor.array.array[2] / 256,
				  l->data->value.asColor.array.array[3] / 256);

			list.append (TQString (tmp));
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;
	    case TypeKey:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			TQString str;
			char *val;
			val = ccsKeyBindingToString (&l->data->value.asKey);

			str = val;
			free (val);

			list.append (str);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;
	    case TypeButton:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			TQString str;
			char *val;
			val = ccsButtonBindingToString (
			          &l->data->value.asButton);

			str = val;
			free (val);

			list.append (str);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;
	    case TypeEdge:
		{
		    TQStringList list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			TQString str;
			char *val;
			val = ccsEdgesToString (l->data->value.asEdge);

			str = val;
			free (val);

			list.append (str);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;
	    case TypeBell:
		{
		    TQValueList<int> list;
		    CCSSettingValueList l;

		    if (!ccsGetList (setting, &l) )
			break;

		    while (l)
		    {
			list.append (l->data->value.asBell);
			l = l->next;
		    }

		    cfg->writeEntry (key, list);
		}
		break;
	    default:
		break;
	    }
	}
	break;

    case TypeKey:
	{
	    CCSSettingKeyValue keyVal;

	    if (!ccsGetKey (setting, &keyVal))
		break;

	    char *val = ccsKeyBindingToString (&keyVal);

	    cfg->writeEntry (key, val);

	    free (val);
	}
	break;
    case TypeButton:
	{
	    CCSSettingButtonValue buttonVal;

	    if (!ccsGetButton (setting, &buttonVal))
		break;

	    char *val = ccsButtonBindingToString (&buttonVal);

	    cfg->writeEntry (key, val);

	    free (val);
	}
	break;
    case TypeEdge:
	{
	    unsigned int edges;

	    if (!ccsGetEdge (setting, &edges) )
		break;

	    char *val = ccsEdgesToString (edges);

	    cfg->writeEntry (key, val);

	    free (val);
	}
	break;
    case TypeBell:
	{
	    Bool bell;

	    if (!ccsGetBell (setting, &bell))
		break;

	    cfg->writeEntry (key, (bell)?true:false);
	}
	break;

    default:
	kdDebug () << "Not supported setting type : " << setting->type << endl;
	break;
    }
}

static Bool
readInit (CCSContext *c)
{
    if (!instance)
	instance = new TDEInstance ("ccs-backend-tdeconfig");

    if (cFiles->profile != ccsGetProfile (c) )
    {
	TQString configName ("compizrc");

	if (ccsGetProfile (c) && strlen (ccsGetProfile (c) ) )
	{
	    configName += ".";
	    configName += ccsGetProfile (c);
	    cFiles->profile = ccsGetProfile (c);
	}

	delete cFiles->main;

	TQString wFile = TDEGlobal::dirs()->saveLocation ("config",
			TQString(), false) + configName;
	createFile (wFile);

	cFiles->main = new KSimpleConfig (configName);
	ccsRemoveFileWatch (cFiles->watch);
	cFiles->watch = ccsAddFileWatch (wFile.ascii(), TRUE,
					 reload, (void *) c);
    }

    return TRUE;
}

static void
readDone (CCSContext *)
{}

static Bool
writeInit (CCSContext *c)
{
    if (!instance)
	instance = new TDEInstance ("ccs-backend-tdeconfig");

    if (cFiles->profile != ccsGetProfile (c) )
    {
	TQString configName ("compizrc");

	if (ccsGetProfile (c) && strlen (ccsGetProfile (c) ) )
	{
	    configName += ".";
	    configName += ccsGetProfile (c);
	    cFiles->profile = ccsGetProfile (c);
	}

	delete cFiles->main;

	TQString wFile = TDEGlobal::dirs()->saveLocation ("config",
			TQString(), false) + configName;

	createFile (wFile);

	cFiles->main = new KSimpleConfig (configName);
	ccsRemoveFileWatch (cFiles->watch);
	cFiles->watch = ccsAddFileWatch (wFile.ascii(), TRUE,
					 reload, (void *) c);
    }

    ccsDisableFileWatch (cFiles->watch);
    ccsDisableFileWatch (cFiles->twinWatch);
    ccsDisableFileWatch (cFiles->globalWatch);

    return TRUE;
}

static void
writeDone (CCSContext *)
{
    cFiles->main->sync();
    if (cFiles->modified)
    {
	cFiles->twin->sync();
	cFiles->global->sync();
	DCOPClient *client = kapp->dcopClient();
	if (!client->isAttached())
	client->attach();
	client->send("twin", "KWinInterface", "reconfigure()", TQString(""));
	cFiles->modified = false;
    }
    ccsEnableFileWatch (cFiles->watch);
    ccsEnableFileWatch (cFiles->twinWatch);
    ccsEnableFileWatch (cFiles->globalWatch);
}


static Bool
init (CCSContext *c)
{
    if (!instance)
	instance = new TDEInstance ("ccs-backend-tdeconfig");

    cFiles = new ConfigFiles;

    TQString configName ("compizrc");

    if (ccsGetProfile (c) && strlen (ccsGetProfile (c) ) )
    {
	configName += ".";
	configName += ccsGetProfile (c);
	cFiles->profile = ccsGetProfile (c);
    }

    TQString wFile = TDEGlobal::dirs()->saveLocation ("config",
		    TQString(), false) + configName;

    createFile (wFile);

    cFiles->main = new KSimpleConfig (configName);
    cFiles->twin   = new TDEConfig ("twinrc");
    cFiles->global = new TDEConfig ("kdeglobals");

    cFiles->twin->setGroup ("Windows");
    cFiles->global->setGroup ("Global Shortcuts");

    cFiles->watch = ccsAddFileWatch (wFile.ascii(), TRUE, reload, (void *) c);

    wFile = TDEGlobal::dirs()->saveLocation ("config",
		    TQString(), false) + "twinrc";
    cFiles->twinWatch = ccsAddFileWatch (wFile.ascii(), TRUE, reload,
					 (void *) c);
    wFile = TDEGlobal::dirs()->saveLocation ("config",
		    TQString(), false) + "kdeglobals";
    cFiles->globalWatch = ccsAddFileWatch (wFile.ascii(), TRUE, reload,
					   (void *) c);

    return TRUE;
}

static Bool
fini (CCSContext *)
{
    if (cFiles)
    {
	ccsRemoveFileWatch (cFiles->watch);
	ccsRemoveFileWatch (cFiles->twinWatch);
	ccsRemoveFileWatch (cFiles->globalWatch);

	if (cFiles->main)
	    delete cFiles->main;

	if (cFiles->twin)
	    delete cFiles->twin;

	if (cFiles->global)
	    delete cFiles->global;

	delete cFiles;
    }

    cFiles = NULL;

    return TRUE;
}

static Bool
deleteProfile (CCSContext *,
	       char       *profile)
{
    TQString file (TDEGlobal::dirs()->saveLocation ("config",
		  TQString(), false) );
    file += "compizrc";

    if (profile && strlen (profile) )
    {
	file += ".";
	file += profile;
    }

    if (TQFile::exists (file) )
	return TQFile::remove (file);

    return FALSE;
}

static CCSBackendVTable tdeconfigVTable =
{
    "tdeconfig",
    "KDE Configuration Backend",
    "KDE Configuration Backend for libccs",
    true,
    true,
    0,
    init,
    fini,
    readInit,
    readSetting,
    readDone,
    writeInit,
    writeSetting,
    writeDone,
    getSettingIsIntegrated,
    getSettingIsReadOnly,
    getExistingProfiles,
    deleteProfile
};

extern "C"
{

    KDE_EXPORT CCSBackendVTable *
    getBackendInfo (void)
    {
	return &tdeconfigVTable;
    }

}