//=========================================== // Lumina-desktop source code // Copyright (c) 2017, Ken Moore // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== #include "DesktopSettings.h" #include #include #include #include #include #include #define FILEPREFIX QString("/lumina-desktop/desktop/") // === PUBLIC === DesktopSettings::DesktopSettings(QObject *parent) : QObject(parent){ watcher = 0; runmode = DesktopSettings::UserFull; } DesktopSettings::~DesktopSettings(){ if(!files.isEmpty()){ stop(); } } DesktopSettings* DesktopSettings::instance(){ static DesktopSettings *set = 0; if(set==0){ //First-time init set = new DesktopSettings(); set->start(); } return set; } //Start/stop routines void DesktopSettings::start(){ files.clear(); settings.clear(); //clear the internal hashes (just in case) if(watcher==0){ watcher = new QFileSystemWatcher(this); connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(fileChanged(QString)) ); connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)) ); } parseSystemSettings(); //set the runmode appropriately locateFiles(); // } void DesktopSettings::stop(){ QStringList watch; watch << watcher->files() << watcher->directories(); if(!watch.isEmpty()){ watcher->removePaths(watch); } files.clear(); //clear the internal hash settings.clear(); } //Main Read/Write functions QList< DesktopSettings::File > DesktopSettings::writableFiles(){ QList< DesktopSettings::File > tmp; if(runmode!=DesktopSettings::SystemFull){ tmp = filesForRunMode(runmode); } return tmp; } QVariant DesktopSettings::value(DesktopSettings::File file, QString variable, QVariant defaultvalue){ if(!files.contains(file)){ return defaultvalue; } for(int i=0; icontains(variable)){ //if this file does not have the variable - go to the next one return settings[files[file][i]]->value(variable, defaultvalue); } } } return defaultvalue; //none of the files contain the variable - return the default } bool DesktopSettings::setValue(DesktopSettings::File file, QString variable, QVariant value){ if(!files.contains(file)){ return false; } for(int i=0; iisWritable() ){ //Check write permissions settings[files[file][i]]->setValue(variable, value); settings[files[file][i]]->sync(); //make sure this is synced to disk ASAP return true; } } } return false; } QStringList DesktopSettings::keys(DesktopSettings::File file){ if(!files.contains(file)){ return QStringList(); } QStringList keyList; for(int i=0; iallKeys(); } } keyList.removeDuplicates(); return keyList; } //Information functions QStringList DesktopSettings::filePaths(DesktopSettings::File file){ if(!files.contains(file)){ return QStringList(); } return files.value(file); } //=== PRIVATE === void DesktopSettings::parseSystemSettings(){ //run at start - determine the RunMode for this user/session //This will also load the DesktopSettings::System file into the hashes runmode = DesktopSettings::UserFull; //default value unless otherwise specified QStringList dirs; dirs << QString(getenv("XDG_CONFIG_DIRS")).split(":") << QString(getenv("XDG_DATA_DIRS")).split(":"); for(int i=0; ivalue("default_mode","fulluser").toString().toLower(); if(defMode=="fullsystem"){ runmode= DesktopSettings::SystemFull; } else if(defMode=="staticinterface"){ runmode = DesktopSettings::SystemInterface; } //Now determine the runmode for this user struct passwd *pw = getpwuid(getuid()); if(pw!=0){ QString cuser = QString(pw->pw_name); free(pw); //done with this structure if( settings[path]->value("fulluser_users", QStringList()).toStringList().contains(cuser) ){ runmode = DesktopSettings::UserFull; } else if( settings[path]->value("fullsystem_users", QStringList()).toStringList().contains(cuser) ){ runmode = DesktopSettings::SystemFull; } else if( settings[path]->value("staticinterface_users", QStringList()).toStringList().contains(cuser) ){ runmode = DesktopSettings::SystemInterface; } else{ //No rule found for this specific user - check the group rules //Read off the list of groups gid_t grpList[100]; int grpSize = 100; if( getgrouplist(cuser.toLocal8Bit(), getgid(), grpList, &grpSize) > 0 ){ QStringList groups; for(int i=0; igr_name); free(g); } } QStringList fromfile = settings[path]->value("fulluser_groups", QStringList()).toStringList(); fromfile.removeDuplicates(); if( (fromfile+groups).removeDuplicates() > 0 ){ runmode = DesktopSettings::UserFull; } else{ fromfile = settings[path]->value("fullsystem_groups", QStringList()).toStringList(); fromfile.removeDuplicates(); if((fromfile+groups).removeDuplicates() > 0 ){ runmode = DesktopSettings::SystemFull; } else{ fromfile = settings[path]->value("staticinterface_groups", QStringList()).toStringList(); fromfile.removeDuplicates(); if((fromfile+groups).removeDuplicates() > 0 ){ runmode = DesktopSettings::SystemInterface; } } } } //end group list read } }else{ runmode = DesktopSettings::SystemFull; //could not read user name - assume system files only } break; //found this file - go ahead and stop now (no hierarchy for this special file) } //Now report the run mode that was detected QString mode; if(runmode == DesktopSettings::UserFull){ mode = "Full User"; } else if(runmode == DesktopSettings::SystemFull){ mode = "Full System"; } else if(runmode == DesktopSettings::SystemInterface){ mode = "System Interface"; } qDebug() << "Detected Lumina Runtime Mode:" << mode; } void DesktopSettings::locateFiles(){ //run at start - finds the locations of the various files (based on RunMode) QString userdir; QStringList systemdirs; userdir = QString(getenv("XDG_CONFIG_HOME")); systemdirs << QString(getenv("XDG_CONFIG_DIRS")).split(":") << QString(getenv("XDG_DATA_DIRS")).split(":"); //Load all the user-level files for this run mode QList< DesktopSettings::File > tmp; if(runmode!=DesktopSettings::SystemFull){ //Load the user-level files tmp= filesForRunMode(runmode); for(int i=0; iaddPath(path); } } //Now load all the system-level files tmp = filesForRunMode(DesktopSettings::SystemFull); for(int i=0; iaddPath(path); } } } } void DesktopSettings::touchFile(QString path){ if(QFile::exists(path)){ return; } //already exists //Make sure the parent directory exists if(!QFile::exists(path.section("/",0,-2)) ){ QDir dir; dir.mkpath(path.section("/",0,-2)); } //Now create the empty file QFile file(path); if( file.open(QIODevice::ReadWrite) ){ //if it opens successfully, then it has created the file file.close(); } } QList< DesktopSettings::File > DesktopSettings::filesForRunMode(RunMode mode){ // Note that the "System" file is always ignored here - that is specially loaded QList< DesktopSettings::File > tmp; if(mode == DesktopSettings::UserFull || mode == DesktopSettings::SystemFull){ tmp << DesktopSettings::Favorites << DesktopSettings::Environment << DesktopSettings::Session << DesktopSettings::Desktop << DesktopSettings::Panels << DesktopSettings::Plugins << DesktopSettings::Keys << DesktopSettings::ContextMenu << DesktopSettings::Animation << DesktopSettings::ScreenSaver << DesktopSettings::WM; }else if(runmode == DesktopSettings::SystemInterface){ tmp << DesktopSettings::Favorites << DesktopSettings::Environment << DesktopSettings::Session; } return tmp; } QString DesktopSettings::rel_path(DesktopSettings::File file){ QString name; switch(file){ case DesktopSettings::System: name="system"; break; case DesktopSettings::Favorites: name="favorites"; break; case DesktopSettings::Environment: name="environment"; break; case DesktopSettings::Session: name="session"; break; case DesktopSettings::Desktop: name="desktop"; break; case DesktopSettings::ContextMenu: name="contextmenu"; break; case DesktopSettings::Keys: name="keys"; break; case DesktopSettings::Animation: name="animations"; break; case DesktopSettings::Panels: name="panels"; break; case DesktopSettings::Plugins: name="plugins"; break; case DesktopSettings::ScreenSaver: name="screensaver"; break; case DesktopSettings::WM: name="windows"; break; } return FILEPREFIX+name+".conf"; } //=== PRIVATE SLOTS === void DesktopSettings::fileChanged(QString file){ //QFileSystemWatcher change detected if(!watcher->files().contains(file)){ //Make sure this file stays watched for changes touchFile(file); watcher->addPath(file); } //Make sure the settings structure for this file is updated to match what is on disk if(settings.contains(file)){ settings[file]->sync(); } //Find which file type this is and send out the signal about it QList< DesktopSettings::File > types = files.keys(); for(int i=0; i