/* * KDE libccs backend * * Copyright (c) 2006 Dennis Kasprzyk * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern "C" { #include #include } #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 KInstance *instance = NULL; typedef struct _ConfigFiles { KSimpleConfig *main; QString profile; KConfig *kwin; KConfig *global; Bool modified; unsigned int watch; unsigned int kwinWatch; unsigned int globalWatch; } ConfigFiles; static ConfigFiles *cFiles = NULL; typedef enum { OptionInt, OptionBool, OptionKey, OptionSpecial } SpecialOptionType; struct _SpecialOption { QString settingName; QString pluginName; QString 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 (QString name) { if (!QFile::exists(name)) { QFile 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->kwinWatch); ccsDisableFileWatch (cFiles->globalWatch); cFiles->main->reparseConfiguration(); cFiles->kwin->reparseConfiguration(); cFiles->global->reparseConfiguration(); ccsReadSettings (context); ccsEnableFileWatch (cFiles->watch); ccsEnableFileWatch (cFiles->kwinWatch); ccsEnableFileWatch (cFiles->globalWatch); } static bool isIntegratedOption (CCSSetting *setting) { for (unsigned int i = 0; i < N_SOPTIONS; i++) { if (setting->name == specialOptions[i].settingName && QString (setting->parent->name) == specialOptions[i].pluginName) return true; } return false; } static void KdeIntToCCS (CCSSetting *setting, int num) { KConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->kwin; int val = cfg->readNumEntry (specialOptions[num].kdeName); ccsSetInt (setting, val); } static void KdeBoolToCCS (CCSSetting *setting, int num) { KConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->kwin; Bool val = (cfg->readBoolEntry (specialOptions[num].kdeName))? TRUE : FALSE; ccsSetBool (setting, val); } static void KdeKeyToCCS (CCSSetting *setting, int num) { KConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->kwin; 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 && QString (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->kwin->readEntry ("FocusPolicy") == "ClickToFocus") ? TRUE : FALSE; ccsSetBool (setting, val); } else if (specialOptions[option].settingName == "number_of_desktops") { cFiles->kwin->setGroup ("Desktops"); KdeIntToCCS (setting, option); cFiles->kwin->setGroup ("Windows"); } else if (specialOptions[option].settingName == "mode" && specialOptions[option].pluginName == "resize") { QString mode = cFiles->kwin->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->kwin->readNumEntry ("WindowSnapZone"); int val2 = cFiles->kwin->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->kwin->readNumEntry ("WindowSnapZone"); int val2 = cFiles->kwin->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->kwin->readEntry ("AltTabStyle") == "KDE"); cFiles->kwin->setGroup ("TabBox"); val1 = cFiles->kwin->readBoolEntry ("TraverseAll"); cFiles->kwin->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->kwin->readEntry ("AltTabStyle") == "KDE"); cFiles->kwin->setGroup ("TabBox"); val1 = cFiles->kwin->readBoolEntry ("TraverseAll"); cFiles->kwin->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->kwin->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->kwin->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->kwin->readNumEntry ("ElectricBorders"); if (val > 1) ccsSetBool (setting, TRUE); else ccsSetBool (setting, FALSE); } else if (specialOptions[option].settingName == "mode" && specialOptions[option].pluginName == "place") { QString mode = cFiles->kwin->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 && QString (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 KInstance ("ccs-backend-kconfig"); QDir dir (KGlobal::dirs()->saveLocation ("config", QString::null, false), "compizrc.*"); QStringList files = dir.entryList(); CCSStringList ret = NULL; QStringList::iterator it; for (it = files.begin(); it != files.end(); it++) { QString str = (*it); if (str.length() > 9) { QString 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; QString key (setting->name); QString group (setting->parent->name); if (setting->isScreen) { group += "_screen"; group += QString::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: { QString 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: { QValueList list = cfg->readIntListEntry (key); Bool *array = new Bool[list.count() ]; int i = 0; QValueList::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: { QValueList list = cfg->readIntListEntry (key); int *array = new int[list.count() ]; int i = 0; QValueList::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: { QStringList list = cfg->readListEntry (key); if (!list.count() ) break; char **array = new char *[list.count() ]; int i = 0; QStringList::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: { QStringList list = cfg->readListEntry (key); if (!list.count() ) break; char **array = new char *[list.count() ]; int i = 0; QStringList::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: { QStringList list = cfg->readListEntry (key); float *array = new float[list.count() ]; int i = 0; QStringList::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: { QStringList list = cfg->readListEntry (key); CCSSettingColorValue *array = new CCSSettingColorValue[list.count() ]; int i = 0; QStringList::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: { QStringList list = cfg->readListEntry (key); CCSSettingValue *val = NULL; CCSSettingValueList l = NULL; QStringList::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: { QStringList list = cfg->readListEntry (key); CCSSettingValue *val = NULL; CCSSettingValueList l = NULL; QStringList::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: { QStringList list = cfg->readListEntry (key); CCSSettingValue *val = NULL; CCSSettingValueList l = NULL; QStringList::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: { QValueList list = cfg->readIntListEntry (key); CCSSettingValue *val = NULL; CCSSettingValueList l = NULL; QValueList::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: { QString str = cfg->readEntry (key); CCSSettingKeyValue value; ccsStringToKeyBinding (str.ascii(), &value); ccsSetKey (setting, value); } break; case TypeButton: { QString str = cfg->readEntry (key); CCSSettingButtonValue value; ccsStringToButtonBinding (str.ascii(), &value); ccsSetButton (setting, value); } break; case TypeEdge: { QString 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) { KConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->kwin; 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) { KConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->kwin; 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) { KConfig *cfg = (specialOptions[num].global) ? cFiles->global : cFiles->kwin; 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 && QString (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") { QString mode = cFiles->kwin->readEntry ("FocusPolicy"); QString val = "ClickToFocus"; Bool bVal; if (!ccsGetBool (setting, &bVal) ) break; if (!bVal) { val = "FocusFollowsMouse"; } if (mode != val) { cFiles->modified = true; cFiles->kwin->writeEntry ("FocusPolicy", val); } } if (specialOptions[option].settingName == "number_of_desktops") { cFiles->kwin->setGroup ("Desktops"); CCSIntToKde (setting, option); cFiles->kwin->setGroup ("Windows"); } if (specialOptions[option].settingName == "mode" && specialOptions[option].pluginName == "resize") { QString mode = cFiles->kwin->readEntry("ResizeMode"); QString val = "Opaque"; int iVal; if (ccsGetInt(setting, &iVal) && (iVal == 1 || iVal == 2)) { val = "Transparent"; } if (mode != val) { cFiles->modified = true; cFiles->kwin->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->kwin->writeEntry ("BorderSnapZone", iVal); else cFiles->kwin->writeEntry ("BorderSnapZone", 0); if (window) cFiles->kwin->writeEntry ("WindowSnapZone", iVal); else cFiles->kwin->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->kwin->setGroup ("TabBox"); cFiles->kwin->writeEntry ("TraverseAll", false); cFiles->kwin->setGroup ("Windows"); cFiles->kwin->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->kwin->setGroup ("TabBox"); cFiles->kwin->writeEntry ("TraverseAll", true); cFiles->kwin->setGroup ("Windows"); cFiles->kwin->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->kwin->writeEntry ("AltTabStyle", "CDE"); cFiles->modified = true; } else if (specialOptions[option].settingName == "edge_flip_window" || specialOptions[option].settingName == "edgeflip_move") { int oVal = cFiles->kwin->readNumEntry ("ElectricBorders"); Bool val; if (!ccsGetBool (setting, &val)) break; if (val) cFiles->kwin->writeEntry ("ElectricBorders", KMAX (1, oVal)); else cFiles->kwin->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->kwin->writeEntry ("ElectricBorders", 2); else cFiles->kwin->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->kwin->writeEntry ("Placement", "Cascade"); break; case 1: cFiles->kwin->writeEntry ("Placement", "Centered"); break; case 2: cFiles->kwin->writeEntry ("Placement", "Smart"); break; case 3: cFiles->kwin->writeEntry ("Placement", "Maximizing"); break; case 4: cFiles->kwin->writeEntry ("Placement", "Random"); break; default: break; } cFiles->modified = true; } break; default: break; } } static void writeSetting (CCSContext *c, CCSSetting *setting) { KSimpleConfig *cfg = cFiles->main; QString key (setting->name); QString group (setting->parent->name); if (setting->isScreen) { group += "_screen"; group += QString::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, QString (tmp)); } break; case TypeList: { switch (setting->info.forList.listType) { case TypeBool: { QValueList 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: { QValueList 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: { QStringList 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: { QStringList 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: { QStringList list; CCSSettingValueList l; if (!ccsGetList (setting, &l) ) break; while (l) { list.append (QString::number (l->data->value.asFloat) ); l = l->next; } cfg->writeEntry (key, list); } break; case TypeColor: { QStringList 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 (QString (tmp)); l = l->next; } cfg->writeEntry (key, list); } break; case TypeKey: { QStringList list; CCSSettingValueList l; if (!ccsGetList (setting, &l) ) break; while (l) { QString 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: { QStringList list; CCSSettingValueList l; if (!ccsGetList (setting, &l) ) break; while (l) { QString 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: { QStringList list; CCSSettingValueList l; if (!ccsGetList (setting, &l) ) break; while (l) { QString 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: { QValueList 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 KInstance ("ccs-backend-kconfig"); if (cFiles->profile != ccsGetProfile (c) ) { QString configName ("compizrc"); if (ccsGetProfile (c) && strlen (ccsGetProfile (c) ) ) { configName += "."; configName += ccsGetProfile (c); cFiles->profile = ccsGetProfile (c); } delete cFiles->main; QString wFile = KGlobal::dirs()->saveLocation ("config", QString::null, 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 KInstance ("ccs-backend-kconfig"); if (cFiles->profile != ccsGetProfile (c) ) { QString configName ("compizrc"); if (ccsGetProfile (c) && strlen (ccsGetProfile (c) ) ) { configName += "."; configName += ccsGetProfile (c); cFiles->profile = ccsGetProfile (c); } delete cFiles->main; QString wFile = KGlobal::dirs()->saveLocation ("config", QString::null, 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->kwinWatch); ccsDisableFileWatch (cFiles->globalWatch); return TRUE; } static void writeDone (CCSContext *) { cFiles->main->sync(); if (cFiles->modified) { cFiles->kwin->sync(); cFiles->global->sync(); DCOPClient *client = kapp->dcopClient(); if (!client->isAttached()) client->attach(); client->send("kwin", "KWinInterface", "reconfigure()", ""); cFiles->modified = false; } ccsEnableFileWatch (cFiles->watch); ccsEnableFileWatch (cFiles->kwinWatch); ccsEnableFileWatch (cFiles->globalWatch); } static Bool init (CCSContext *c) { if (!instance) instance = new KInstance ("ccs-backend-kconfig"); cFiles = new ConfigFiles; QString configName ("compizrc"); if (ccsGetProfile (c) && strlen (ccsGetProfile (c) ) ) { configName += "."; configName += ccsGetProfile (c); cFiles->profile = ccsGetProfile (c); } QString wFile = KGlobal::dirs()->saveLocation ("config", QString::null, false) + configName; createFile (wFile); cFiles->main = new KSimpleConfig (configName); cFiles->kwin = new KConfig ("kwinrc"); cFiles->global = new KConfig ("kdeglobals"); cFiles->kwin->setGroup ("Windows"); cFiles->global->setGroup ("Global Shortcuts"); cFiles->watch = ccsAddFileWatch (wFile.ascii(), TRUE, reload, (void *) c); wFile = KGlobal::dirs()->saveLocation ("config", QString::null, false) + "kwinrc"; cFiles->kwinWatch = ccsAddFileWatch (wFile.ascii(), TRUE, reload, (void *) c); wFile = KGlobal::dirs()->saveLocation ("config", QString::null, false) + "kdeglobals"; cFiles->globalWatch = ccsAddFileWatch (wFile.ascii(), TRUE, reload, (void *) c); return TRUE; } static Bool fini (CCSContext *) { if (cFiles) { ccsRemoveFileWatch (cFiles->watch); ccsRemoveFileWatch (cFiles->kwinWatch); ccsRemoveFileWatch (cFiles->globalWatch); if (cFiles->main) delete cFiles->main; if (cFiles->kwin) delete cFiles->kwin; if (cFiles->global) delete cFiles->global; delete cFiles; } cFiles = NULL; return TRUE; } static Bool deleteProfile (CCSContext *, char *profile) { QString file (KGlobal::dirs()->saveLocation ("config", QString::null, false) ); file += "compizrc"; if (profile && strlen (profile) ) { file += "."; file += profile; } if (QFile::exists (file) ) return QFile::remove (file); return FALSE; } static CCSBackendVTable kconfigVTable = { "kconfig", "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" { CCSBackendVTable * getBackendInfo (void) { return &kconfigVTable; } }