//=========================================== // Lumina-DE source code // Copyright (c) 2013, Ken Moore // Available under the 3-clause BSD license // See the LICENSE file for full details //=========================================== #include "LuminaXDG.h" #include "LuminaOS.h" #include #include static QStringList mimeglobs; static qint64 mimechecktime; //==== LXDG Functions ==== XDGDesktop LXDG::loadDesktopFile(QString filePath, bool& ok){ //Create the outputs ok=false; XDGDesktop DF; DF.isHidden=false; DF.useTerminal=false; DF.startupNotify=false; DF.type = XDGDesktop::APP; DF.filePath = filePath; DF.exec = DF.tryexec = ""; // just to make sure this is initialized //Check input file path validity QFile file(filePath); if(!file.exists()){ return DF; } //invalid file //Get the current localization code QString lang = QLocale::system().name(); //lang code //Open the file if(!file.open(QIODevice::Text | QIODevice::ReadOnly)){ return DF; } QTextStream os(&file); //Read in the File bool insection=false; while(!os.atEnd()){ QString line = os.readLine(); //Check that this is the entry portion of the file (not the action/other sections) if(line=="[Desktop Entry]"){ insection=true; continue; } else if(line.startsWith("[")){ insection=false; } if(!insection || line.startsWith("#")){ continue; } //Now parse out the file line = line.simplified(); QString var = line.section("=",0,0).simplified(); QString loc = var.section("[",1,1).section("]",0,0).simplified(); // localization var = var.section("[",0,0).simplified(); //remove the localization QString val = line.section("=",1,50).simplified(); //------------------- if(var=="Name"){ if(DF.name.isEmpty() && loc.isEmpty()){ DF.name = val; } else if(loc == lang){ DF.name = val; } }else if(var=="GenericName"){ if(DF.genericName.isEmpty() && loc.isEmpty()){ DF.genericName = val; } else if(loc == lang){ DF.genericName = val; } }else if(var=="Comment"){ if(DF.comment.isEmpty() && loc.isEmpty()){ DF.comment = val; } else if(loc == lang){ DF.comment = val; } }else if(var=="Icon"){ if(DF.icon.isEmpty() && loc.isEmpty()){ DF.icon = val; } else if(loc == lang){ DF.icon = val; } } else if( (var=="TryExec") && (DF.tryexec.isEmpty()) ) { DF.tryexec = val; } else if( (var=="Exec") && (DF.exec.isEmpty() ) ) { DF.exec = val; } // only take the first Exec command in the file else if( (var=="Path") && (DF.path.isEmpty() ) ){ DF.path = val; } else if(var=="NoDisplay" && !DF.isHidden){ DF.isHidden = (val.toLower()=="true"); } else if(var=="Hidden" && !DF.isHidden){ DF.isHidden = (val.toLower()=="true"); } else if(var=="Categories"){ DF.catList = val.split(";",QString::SkipEmptyParts); } else if(var=="OnlyShowIn"){ DF.showInList = val.split(";",QString::SkipEmptyParts); } else if(var=="NotShowIn"){ DF.notShowInList = val.split(";",QString::SkipEmptyParts); } else if(var=="Terminal"){ DF.useTerminal= (val.toLower()=="true"); } else if(var=="Actions"){ DF.actionList = val.split(";",QString::SkipEmptyParts); } else if(var=="MimeType"){ DF.mimeList = val.split(";",QString::SkipEmptyParts); } else if(var=="Keywords"){ if(DF.keyList.isEmpty() && loc.isEmpty()){ DF.keyList = val.split(";",QString::SkipEmptyParts); } else if(loc == lang){ DF.keyList = val.split(";",QString::SkipEmptyParts); } } else if(var=="StartupNotify"){ DF.startupNotify = (val.toLower()=="true"); } else if(var=="StartupWMClass"){ DF.startupWM = val; } else if(var=="URL"){ DF.url = val;} else if(var=="Type"){ if(val.toLower()=="application"){ DF.type = XDGDesktop::APP; } else if(val.toLower()=="link"){ DF.type = XDGDesktop::LINK; } else if(val.toLower()=="dir"){ DF.type = XDGDesktop::DIR; } else{ DF.type = XDGDesktop::BAD; } //Unknown type } } //end reading file file.close(); //If there are OnlyShowIn desktops listed, add them to the name if(!DF.showInList.isEmpty()){ DF.name.append(" ("+DF.showInList.join(", ")+")"); } //Quick fix for showing "wine" applications (which quite often don't list a category) if(DF.catList.isEmpty() && filePath.contains("/wine/")){ DF.catList << "Wine"; //Internal Lumina category only (not in XDG specs as of 11/14/14) } //Return the structure ok=true; return DF; } bool LXDG::checkValidity(XDGDesktop dFile, bool showAll){ bool ok=true; bool DEBUG = false; if(DEBUG){ qDebug() << "[LXDG] Check File validity:" << dFile.name << dFile.filePath; } switch (dFile.type){ case XDGDesktop::BAD: ok=false; if(DEBUG){ qDebug() << " - Bad file type"; } break; case XDGDesktop::APP: if(!dFile.tryexec.isEmpty() && !LXDG::checkExec(dFile.tryexec)){ ok=false; if(DEBUG){ qDebug() << " - tryexec does not exist";} } else if(dFile.exec.isEmpty() || dFile.name.isEmpty()){ ok=false; if(DEBUG){ qDebug() << " - exec or name is empty";} } else if(!LXDG::checkExec(dFile.exec.section(" ",0,0,QString::SectionSkipEmpty)) ){ ok=false; if(DEBUG){ qDebug() << " - first exec binary does not exist";} } break; case XDGDesktop::LINK: ok = !dFile.url.isEmpty(); if(DEBUG && !ok){ qDebug() << " - Link with missing URL"; } break; case XDGDesktop::DIR: ok = !dFile.path.isEmpty(); if(DEBUG && !ok){ qDebug() << " - Dir with missing path"; } break; default: ok=false; if(DEBUG){ qDebug() << " - Unknown file type"; } } if(!showAll){ if(!dFile.showInList.isEmpty()){ ok = dFile.showInList.contains("Lumina", Qt::CaseInsensitive); } else if(!dFile.notShowInList.isEmpty()){ ok = !dFile.notShowInList.contains("Lumina",Qt::CaseInsensitive); } } return ok; } bool LXDG::checkExec(QString exec){ //Return true(good) or false(bad) if(exec.startsWith("/")){ return QFile::exists(exec); } else{ QStringList paths = QString(getenv("PATH")).split(":"); for(int i=0; i LXDG::systemDesktopFiles(bool showAll, bool showHidden){ //Returns a list of all the unique *.desktop files that were found QStringList appDirs = LXDG::systemApplicationDirs(); QStringList found; //for avoiding duplicate apps QList out; bool ok; //for internal use only for(int i=0; i > LXDG::sortDesktopCats(QList apps){ //Sort the list of applications into their different categories (main categories only) //Create the category lists QList multimedia, dev, ed, game, graphics, network, office, science, settings, sys, utility, other, wine; //Sort the apps into the lists for(int i=0; i > out; if(!multimedia.isEmpty()){ out.insert("Multimedia", LXDG::sortDesktopNames(multimedia)); } if(!dev.isEmpty()){ out.insert("Development", LXDG::sortDesktopNames(dev)); } if(!ed.isEmpty()){ out.insert("Education", LXDG::sortDesktopNames(ed)); } if(!game.isEmpty()){ out.insert("Game", LXDG::sortDesktopNames(game)); } if(!graphics.isEmpty()){ out.insert("Graphics", LXDG::sortDesktopNames(graphics)); } if(!network.isEmpty()){ out.insert("Network", LXDG::sortDesktopNames(network)); } if(!office.isEmpty()){ out.insert("Office", LXDG::sortDesktopNames(office)); } if(!science.isEmpty()){ out.insert("Science", LXDG::sortDesktopNames(science)); } if(!settings.isEmpty()){ out.insert("Settings", LXDG::sortDesktopNames(settings)); } if(!sys.isEmpty()){ out.insert("System", LXDG::sortDesktopNames(sys)); } if(!utility.isEmpty()){ out.insert("Utility", LXDG::sortDesktopNames(utility)); } if(!wine.isEmpty()){ out.insert("Wine", LXDG::sortDesktopNames(wine)); } if(!other.isEmpty()){ out.insert("Unsorted", LXDG::sortDesktopNames(other)); } //return the resulting hash return out; } QList LXDG::sortDesktopNames(QList apps){ //Sort the list by name of the application QHash sorter; for(int i=0; i out; for(int i=0; i 0){ out << D.absolutePath(); } for(int i=0; i 0){ out << pngs; } } return out; } QStringList LXDG::systemMimeDirs(){ //Returns a list of all the directories where *.xml MIME files can be found QStringList appDirs = QString(getenv("XDG_DATA_HOME")).split(":"); appDirs << QString(getenv("XDG_DATA_DIRS")).split(":"); if(appDirs.isEmpty()){ appDirs << "/usr/local/share" << "/usr/share"; } //Now create a valid list QStringList out; for(int i=0; i