diff options
Diffstat (limited to 'src-qt5/core/libLumina/DesktopSettings.cpp')
-rw-r--r-- | src-qt5/core/libLumina/DesktopSettings.cpp | 255 |
1 files changed, 255 insertions, 0 deletions
diff --git a/src-qt5/core/libLumina/DesktopSettings.cpp b/src-qt5/core/libLumina/DesktopSettings.cpp new file mode 100644 index 00000000..bfd149ca --- /dev/null +++ b/src-qt5/core/libLumina/DesktopSettings.cpp @@ -0,0 +1,255 @@ +//=========================================== +// 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 <QFile> +#include <QDir> +#include <QDebug> + +#include <unistd.h> +#include <pwd.h> +#include <grp.h> + +#define FILEPREFIX QString("/lumina-desktop/desktop/") + +// === PUBLIC === +DesktopSettings::DesktopSettings(QObject *parent) : QObject(parent){ + watcher = 0; + runmode = DesktopSettings::UserFull; +} + +DesktopSettings::~DesktopSettings(){ + if(!files.isEmpty()){ stop(); } +} + +//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 +QVariant DesktopSettings::value(DesktopSettings::File file, QString variable, QVariant defaultvalue){ + if(!files.contains(file)){ return defaultvalue; } + for(int i=0; i<files[file].length(); i++){ + if( settings.contains(files[file][i])){ //make sure this file is in the settings hash + if(settings[files[file][i]]->contains(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; i<files[file].length(); i++){ + if( settings.contains(files[file][i])){ //make sure this file is in the settings hash + if(settings[files[file][i]]->isWritable() ){ //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; i<files[file].length(); i++){ + if( settings.contains(files[file][i])){ //make sure this file is in the settings hash + keyList << settings[files[file][i]]->allKeys(); + } + } + 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; i<dirs.length(); i++){ + if(dirs[i].endsWith("/xdg")){ dirs[i] = dirs[i].section("/",0,-2); } //Chop off the xdg subdir - need the generic configuration directory + QString path = dirs[i]+rel_path(DesktopSettings::System); + if(!QFile::exists(path)){ continue; } + //Load the system file into the hashes + files.insert(DesktopSettings::System, QStringList() << path); + settings.insert(path, new QSettings(path, QSettings::IniFormat, this) ); + //Read off the default mode for the system + QString defMode = settings[path]->value("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; i<grpSize; i++){ + struct group *g = getgrgid(grpList[i]); + if(g!=0){ + groups << QString(g->gr_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"))+"/lumina-desktop"; + 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::UserFull){ tmp << DesktopSettings::Favorites << DesktopSettings::Environment << DesktopSettings::Session << DesktopSettings::Desktop << DesktopSettings::Keys << DesktopSettings::Theme; } + else if(runmode == DesktopSettings::SystemInterface){ tmp << DesktopSettings::Favorites << DesktopSettings::Environment << DesktopSettings::Session << DesktopSettings::Desktop << DesktopSettings::Keys << DesktopSettings::Theme; } + for(int i=0; i<tmp.length(); i++){ + QString path = userdir+rel_path(tmp[i]); + touchFile(path); + files.insert(tmp[i], QStringList() << path); + settings.insert(path, new QSettings(path, QSettings::IniFormat, this) ); + watcher->addPath(path); + } + //Now load all the system-level files + tmp.clear(); + tmp << DesktopSettings::Favorites << DesktopSettings::Environment << DesktopSettings::Session << DesktopSettings::Desktop << DesktopSettings::Keys << DesktopSettings::Theme; + for(int i=0; i<systemdirs.length(); i++){ + if(systemdirs[i].endsWith("/xdg")){ systemdirs[i] = systemdirs[i].section("/",0,-2); } + if( !QFile::exists(systemdirs[i]+"/lumina-desktop") ){ continue; } + for(int j=0; j<tmp.length(); j++){ + QString path = systemdirs[i]+rel_path(tmp[j]); + if(QFile::exists(path)){ + files.insert(tmp[j], QStringList() << path); + settings.insert(path, new QSettings(path, QSettings::IniFormat, this) ); + watcher->addPath(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(); + } +} + +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::Keys: + name="keys"; break; + case DesktopSettings::Theme: + name="theme"; 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<types.length(); i++){ + if(files[types[i]].contains(file)){ + emit FileModified(types[i]); + break; + } + } +} + +void DesktopSettings::dirChanged(QString){ + //Not used yet - placeholder in case we need it later on +} |