1 //===========================================
2 //  Lumina-DE source code
3 //  Copyright (c) 2014-2015, Ken Moore
4 //  Available under the 3-clause BSD license
5 //  See the LICENSE file for full details
6 //===========================================
7 #include "LuminaThemes.h"
8 
9 #include "LUtils.h"
10 #include "LuminaOS.h"
11 #include <QIcon>
12 #include <QFont>
13 #include <QDebug>
14 #include <QObject>
15 #include <QPainter>
16 #include <QPen>
17 
18 #include "LuminaXDG.h"
19 
20 #include <unistd.h>
21 
22 //Stuff necesary for Qt Cursor Reloads
23 //#include "qxcbcursor.h" //needed to prod Qt to refresh the mouse cursor theme
24 //#include <QCursor>
25 
availableSystemThemes()26 QStringList LTHEME::availableSystemThemes(){
27   //returns: [name::::path] for each item
28   QDir dir(LOS::LuminaShare()+"../lthemeengine/desktop_qss");
29   QStringList list = dir.entryList(QStringList() <<"*.qss", QDir::Files, QDir::Name);
30   for(int i=0; i<list.length(); i++){
31     //Format the output entry [<name>::::<fullpath>]
32     list[i] = list[i].section(".qss",0,0)+"::::"+dir.absoluteFilePath(list[i]);
33   }
34   return list;
35 }
36 
availableSystemStyles()37 QStringList LTHEME::availableSystemStyles(){
38   //returns: [name::::path] for each item
39   QDir dir(LOS::LuminaShare()+"../lthemeengine/qss");
40   QStringList list = dir.entryList(QStringList() <<"*.qss", QDir::Files, QDir::Name);
41   for(int i=0; i<list.length(); i++){
42     //Format the output entry [<name>::::<fullpath>]
43     list[i] = list[i].section(".qss",0,0)+"::::"+dir.absoluteFilePath(list[i]);
44   }
45   return list;
46 }
47 
availableLocalThemes()48 QStringList LTHEME::availableLocalThemes(){	//returns: [name::::path] for each item
49   QDir dir( QString(getenv("XDG_CONFIG_HOME"))+"/lthemeengine/desktop_qss");
50   QStringList list = dir.entryList(QStringList() <<"*.qss", QDir::Files, QDir::Name);
51   for(int i=0; i<list.length(); i++){
52     //Format the output entry [<name>::::<fullpath>]
53     list[i] = list[i].section(".qss",0,0)+"::::"+dir.absoluteFilePath(list[i]);
54   }
55   return list;
56 }
57 
availableLocalStyles()58 QStringList LTHEME::availableLocalStyles(){	//returns: [name::::path] for each item
59   QDir dir( QString(getenv("XDG_CONFIG_HOME"))+"/lthemeengine/qss");
60   QStringList list = dir.entryList(QStringList() <<"*.qss", QDir::Files, QDir::Name);
61   for(int i=0; i<list.length(); i++){
62     //Format the output entry [<name>::::<fullpath>]
63     list[i] = list[i].section(".qss",0,0)+"::::"+dir.absoluteFilePath(list[i]);
64   }
65   return list;
66 }
67 
availableSystemColors()68 QStringList LTHEME::availableSystemColors(){ 	//returns: [name::::path] for each item
69   //returns: [name::::path] for each item
70   QDir dir(LOS::LuminaShare()+"../lthemeengine/colors");
71   QStringList list = dir.entryList(QStringList() <<"*.conf", QDir::Files, QDir::Name);
72   for(int i=0; i<list.length(); i++){
73     //Format the output entry [<name>::::<fullpath>]
74     list[i] = list[i].section(".conf",0,0)+"::::"+dir.absoluteFilePath(list[i]);
75   }
76   return list;
77 }
78 
availableLocalColors()79 QStringList LTHEME::availableLocalColors(){ 	//returns: [name::::path] for each item
80   QDir dir(QString(getenv("XDG_CONFIG_HOME"))+"/lthemeengine/colors");
81   QStringList list = dir.entryList(QStringList() <<"*.conf", QDir::Files, QDir::Name);
82   for(int i=0; i<list.length(); i++){
83     //Format the output entry [<name>::::<fullpath>]
84     list[i] = list[i].section(".conf",0,0)+"::::"+dir.absoluteFilePath(list[i]);
85   }
86   return list;
87 }
88 
availableSystemIcons()89 QStringList LTHEME::availableSystemIcons(){ 	//returns: [name] for each item
90   QStringList paths;
91   paths << QDir::homePath()+"/.icons";
92   QStringList xdd = QString(getenv("XDG_DATA_HOME")).split(":");
93   xdd << QString(getenv("XDG_DATA_DIRS")).split(":");
94   for(int i=0; i<xdd.length(); i++){
95     if(QFile::exists(xdd[i]+"/icons")){
96       paths << xdd[i]+"/icons";
97     }
98   }
99   //Now get all the icon themes in these directories
100   QStringList themes, tmpthemes;
101   QDir dir;
102   for(int i=0; i<paths.length(); i++){
103     if(dir.cd(paths[i])){
104        tmpthemes = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
105        for(int j=0; j<tmpthemes.length(); j++){
106 	 if(tmpthemes[j].startsWith("default")){ continue; }
107          if( (QFile::exists(dir.absoluteFilePath(tmpthemes[j]+"/index.theme")) ||
108 		QFile::exists(dir.absoluteFilePath(tmpthemes[j]+"/index.desktop")) ) ){ themes << tmpthemes[j]; }
109        }
110     }
111   }
112   themes.removeDuplicates();
113   themes.sort();
114   return themes;
115 }
116 
availableSystemCursors()117 QStringList LTHEME::availableSystemCursors(){	//returns: [name] for each item
118  QStringList paths;
119   paths << QDir::homePath()+"/.icons";
120   QStringList xdd = QString(getenv("XDG_DATA_HOME")).split(":");
121   xdd << QString(getenv("XDG_DATA_DIRS")).split(":");
122   for(int i=0; i<xdd.length(); i++){
123     if(QFile::exists(xdd[i]+"/icons")){
124       paths << xdd[i]+"/icons";
125     }
126   }
127   //Now get all the icon themes in these directories
128   QStringList themes, tmpthemes;
129   QDir dir;
130   for(int i=0; i<paths.length(); i++){
131     if(dir.cd(paths[i])){
132        tmpthemes = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name);
133        for(int j=0; j<tmpthemes.length(); j++){
134 	 if(tmpthemes[j].startsWith("default")){ continue; }
135          if( QFile::exists(dir.absoluteFilePath(tmpthemes[j]+"/cursors")) ){ themes << tmpthemes[j]; }
136        }
137     }
138   }
139   themes.removeDuplicates();
140   themes.sort();
141   return themes;
142 }
143 
144 //Save a new theme/color file
saveLocalTheme(QString name,QStringList contents)145 bool LTHEME::saveLocalTheme(QString name, QStringList contents){
146   Q_UNUSED(name);
147   Q_UNUSED(contents);
148   return false; //old format - do not use!!
149   //QString localdir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/themes/";
150   //if(!QFile::exists(localdir)){  QDir dir; dir.mkpath(localdir); }
151   //return LUtils::writeFile(localdir+name+".qss.template", contents, true);
152 }
153 
saveLocalColors(QString name,QStringList contents)154 bool LTHEME::saveLocalColors(QString name, QStringList contents){
155   Q_UNUSED(name);
156   Q_UNUSED(contents);
157   return false; //old format - do not use!!
158  // QString localdir = QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/colors/";
159   //if(!QFile::exists(localdir)){  QDir dir; dir.mkpath(localdir); }
160   //return LUtils::writeFile(localdir+name+".qss.colors", contents, true);
161 }
162 
163 //Return the currently selected Theme/Colors/Icons
currentSettings()164 QStringList LTHEME::currentSettings(){ //returns [theme path, colorspath, iconsname, font, fontsize]
165   QStringList out; out << "" << "" << "" << "" << "";
166   QStringList settings = LUtils::readFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/themesettings.cfg");
167   for(int i=0; i<settings.length(); i++){
168     if(settings[i].startsWith("THEMEFILE=")){ out[0] = settings[i].section("=",1,1).simplified(); }
169     else if(settings[i].startsWith("COLORFILE=")){ out[1] = settings[i].section("=",1,1).simplified(); }
170     //else if(settings[i].startsWith("ICONTHEME=")){ out[2] = settings[i].section("=",1,1).simplified(); }
171     else if(settings[i].startsWith("FONTFAMILY=")){ out[3] = settings[i].section("=",1,1).simplified(); }
172     else if(settings[i].startsWith("FONTSIZE=")){ out[4] = settings[i].section("=",1,1).simplified(); }
173   }
174   QSettings engineset("lthemeengine","lthemeengine");
175   out[2]=engineset.value("Appearance/icon_theme", "material-design-light").toString();
176   bool nofile = settings.isEmpty();
177   if(out[0].isEmpty() || !QFile::exists(out[0]) ){ out[0] = LOS::LuminaShare()+"themes/Lumina-default.qss.template"; }
178   if(out[1].isEmpty() || !QFile::exists(out[1]) ){ out[1] = LOS::LuminaShare()+"colors/Lumina-Glass.qss.colors"; }
179   if(out[3].isEmpty()){ out[3] = QFont().defaultFamily(); }
180   if(out[4].isEmpty()){
181     int num = QFont().pointSize(); out[4] = QString::number(num)+"pt"; //Check point size first
182     if(num<0){ num = QFont().pixelSize(); out[4] = QString::number(num)+"px";} //Now check pixel size
183     if(num<0){ out[4] = "9pt"; } //Now hard-code a fallback (just in case)
184   }
185   if(nofile){ setCurrentSettings(out[0], out[1], out[2], out[3], out[4]); }
186 
187   return out;
188 }
189 
190 //Return the currently-selected Cursor theme
currentCursor()191 QString LTHEME::currentCursor(){
192   //qDebug() << "Reading Current Cursor Theme:";
193   QStringList info = LUtils::readFile(QDir::homePath()+"/.icons/default/index.theme");
194   if(info.isEmpty()){ return ""; }
195   QString cursor;
196   bool insection = false;
197   for(int i=0; i<info.length(); i++){
198     if(info[i]=="[Icon Theme]"){ insection = true; continue;}
199     else if(insection && info[i].startsWith("Inherits=")){
200       cursor = info[i].section("=",1,1).simplified();
201       break;
202     }
203   }
204   //qDebug() << " - found theme:" << cursor;
205   return cursor;
206 }
207 
208   //Change the current Theme/Colors/Icons
setCurrentSettings(QString themepath,QString colorpath,QString iconname,QString font,QString fontsize)209 bool LTHEME::setCurrentSettings(QString themepath, QString colorpath, QString iconname, QString font, QString fontsize){
210   Q_UNUSED(font);
211   Q_UNUSED(fontsize);
212   //QIcon::setThemeName(iconname);
213   //Save these settings into the theme engine settings
214   QSettings engineset("lthemeengine","lthemeengine");
215   engineset.setValue("Appearance/icon_theme", iconname);
216   engineset.setValue("Appearance/custom_palette", QFile::exists(colorpath) );
217   engineset.setValue("Appearance/color_scheme_path", colorpath);
218   engineset.setValue("Interface/desktop_stylesheets", QStringList() << themepath);
219   return true;
220   //Now save the theme settings file
221   /*QStringList contents;
222 	contents << "THEMEFILE="+themepath;
223 	contents << "COLORFILE="+colorpath;
224 	contents << "ICONTHEME="+iconname;
225 	contents << "FONTFAMILY="+font;
226 	contents << "FONTSIZE="+fontsize;
227   bool ok = LUtils::writeFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/themesettings.cfg", contents, true);
228   return ok;*/
229 }
230 
231 //Change the current Cursor Theme
setCursorTheme(QString cursorname)232 bool LTHEME::setCursorTheme(QString cursorname){
233 //qDebug() << "Set Cursor Theme:" << cursorname;
234   if(cursorname=="default"){
235     //special case - this will cause a recursive inheritance loop - just remove the file instead
236     if(QFile::exists(QDir::homePath()+"/.icons/default/index.theme")){
237       return QFile::remove(QDir::homePath()+"/.icons/default/index.theme");
238     }
239     return true; //already does not exist
240   }
241   QStringList info = LUtils::readFile(QDir::homePath()+"/.icons/default/index.theme");
242     bool insection = false;
243     bool changed = false;
244     QString newval = "Inherits="+cursorname;
245     for(int i=0; i<info.length() && !changed; i++){
246       if(info[i]=="[Icon Theme]"){
247 	insection = true;
248       }else if( info[i].startsWith("[") && insection){
249 	//Section does not have the setting - add it
250 	info.insert(i, newval);
251 	changed =true;
252       }else if( info[i].startsWith("[") ){
253 	insection = false;
254       }else if(insection && info[i].startsWith("Inherits=")){
255         info[i] = newval; //replace the current setting
256         changed = true;
257       }
258     } //end loop over file contents
259     if(!changed){ //Could not change the file contents for some reason
260       if(insection){ info << newval; } //end of file while in the section
261       else{ info << "[Icon Theme]" << newval; } //entire section missing from file
262     }
263     //Now save the file
264     //qDebug() << "Done saving the cursor:" << info;
265     return LUtils::writeFile(QDir::homePath()+"/.icons/default/index.theme", info, true);
266 }
267 
setCurrentStyles(QStringList paths)268 bool LTHEME::setCurrentStyles(QStringList paths){
269   //Verify that the paths are all absolute paths, otherwise scan/replace with absolute paths
270   QStringList avail = LTHEME::availableSystemStyles();
271   for(int i=0; i<paths.length(); i++){
272     paths[i] = paths[i].simplified();
273     if(paths[i].startsWith("/")){ continue; } //already an absolute path
274     for(int j=0; j<avail.length(); j++){
275       if(avail[j].startsWith(paths[i].section("/",-1).section(".qss",0,0)+"::::") ){ paths[i] = avail[j].section("::::",1,-1); break; }
276     }
277   }
278   //ordered by priority: lowest -> highest
279   QSettings engineset("lthemeengine","lthemeengine");
280   engineset.setValue("Interface/stylesheets",paths);
281   engineset.sync();
282   return true;
283 }
284 
285   //Return the complete stylesheet for a given theme/colors
assembleStyleSheet(QString themepath,QString colorpath,QString font,QString fontsize)286 QString LTHEME::assembleStyleSheet(QString themepath, QString colorpath, QString font, QString fontsize){
287   QString stylesheet = LUtils::readFile(themepath).join("\n");
288   QStringList colors = LUtils::readFile(colorpath);
289   //qDebug() << "Found Theme:" << themepath << stylesheet;
290   //qDebug() << "Found Colors:" << colorpath << colors;
291   QStringList systhemes = availableSystemThemes();
292   QStringList locthemes = availableLocalThemes();
293   //Now do any inheritance between themes
294   int start = stylesheet.indexOf("INHERITS=");
295   while(start>=0){
296     QString line = stylesheet.mid(start, stylesheet.indexOf("\n",start)-start); //only get this line
297     QString inherit = line.section("=",1,1);
298     QString rStyle; //replacement stylesheet
299     if(!locthemes.filter(inherit+"::::").isEmpty()){
300        rStyle = LUtils::readFile(locthemes.filter(inherit+"::::").first().section("::::",1,1)).join("\n");
301     }else if(!systhemes.filter(inherit+"::::").isEmpty()){
302       rStyle = LUtils::readFile(systhemes.filter(inherit+"::::").first().section("::::",1,1)).join("\n");
303     }
304     stylesheet.replace(line, rStyle);
305     //Now look for the next one
306     start = stylesheet.indexOf("INHERITS=");
307   }
308   //Now perform the color replacements
309   for(int i=0; i<colors.length(); i++){
310     if(colors[i].isEmpty() || colors[i].startsWith("#")){ continue; }
311     else if(colors[i].startsWith("PRIMARYCOLOR=")){ stylesheet = stylesheet.replace("%%PRIMARYCOLOR%%", colors[i].section("=",1,1).simplified()); }
312     else if(colors[i].startsWith("SECONDARYCOLOR=")){ stylesheet = stylesheet.replace("%%SECONDARYCOLOR%%", colors[i].section("=",1,1).simplified()); }
313     else if(colors[i].startsWith("HIGHLIGHTCOLOR=")){ stylesheet = stylesheet.replace("%%HIGHLIGHTCOLOR%%", colors[i].section("=",1,1).simplified()); }
314     else if(colors[i].startsWith("ACCENTCOLOR=")){ stylesheet = stylesheet.replace("%%ACCENTCOLOR%%", colors[i].section("=",1,1).simplified()); }
315     else if(colors[i].startsWith("PRIMARYDISABLECOLOR=")){ stylesheet = stylesheet.replace("%%PRIMARYDISABLECOLOR%%", colors[i].section("=",1,1).simplified()); }
316     else if(colors[i].startsWith("SECONDARYDISABLECOLOR=")){ stylesheet = stylesheet.replace("%%SECONDARYDISABLECOLOR%%", colors[i].section("=",1,1).simplified()); }
317     else if(colors[i].startsWith("HIGHLIGHTDISABLECOLOR=")){ stylesheet = stylesheet.replace("%%HIGHLIGHTDISABLECOLOR%%", colors[i].section("=",1,1).simplified()); }
318     else if(colors[i].startsWith("ACCENTDISABLECOLOR=")){ stylesheet = stylesheet.replace("%%ACCENTDISABLECOLOR%%", colors[i].section("=",1,1).simplified()); }
319     else if(colors[i].startsWith("BASECOLOR=")){ stylesheet = stylesheet.replace("%%BASECOLOR%%", colors[i].section("=",1,1).simplified()); }
320     else if(colors[i].startsWith("ALTBASECOLOR=")){ stylesheet = stylesheet.replace("%%ALTBASECOLOR%%", colors[i].section("=",1,1).simplified()); }
321     else if(colors[i].startsWith("TEXTCOLOR=")){ stylesheet = stylesheet.replace("%%TEXTCOLOR%%", colors[i].section("=",1,1).simplified()); }
322     else if(colors[i].startsWith("TEXTDISABLECOLOR=")){ stylesheet = stylesheet.replace("%%TEXTDISABLECOLOR%%", colors[i].section("=",1,1).simplified()); }
323     else if(colors[i].startsWith("TEXTHIGHLIGHTCOLOR=")){ stylesheet = stylesheet.replace("%%TEXTHIGHLIGHTCOLOR%%", colors[i].section("=",1,1).simplified()); }
324   }
325   stylesheet = stylesheet.replace("%%FONT%%", "\""+font+"\"");
326   stylesheet = stylesheet.replace("%%FONTSIZE%%", fontsize);
327   //qDebug() << "Assembled Style Sheet:\n" << stylesheet;
328   return stylesheet;
329 }
330 // Extra information about a cursor theme
cursorInformation(QString name)331 QStringList LTHEME::cursorInformation(QString name){
332   //returns: [Name, Comment, Sample Image File]
333   QStringList out; out << "" << "" << ""; //ensure consistent output structure
334   QStringList paths; paths << LOS::SysPrefix()+"lib/X11/icons/" << LOS::AppPrefix()+"lib/X11/icons/";
335   for(int i=0; i<paths.length(); i++){
336     if(QFile::exists(paths[i]+name)){
337       if(QFile::exists(paths[i]+name+"/cursors/arrow")){ out[2] = paths[i]+name+"/cursors/arrow"; }
338       QStringList info = LUtils::readFile(paths[i]+name+"/index.theme");
339       for(int j=info.indexOf("[Icon Theme]"); j<info.length(); j++){
340 	if(j<0){continue; } //just in case the index function errors out
341 	if(info[j].startsWith("Name") && info[j].contains("=")){ out[0] = info[j].section("=",1,1).simplified(); }
342 	else if(info[j].startsWith("Comment") && info[j].contains("=")){ out[1] = info[j].section("=",1,1).simplified(); }
343       }
344       break; //found the cursor
345     }
346   }
347   return out;
348 }
349 
CustomEnvSettings(bool useronly)350 QStringList LTHEME::CustomEnvSettings(bool useronly){ //view all the key=value settings
351   QStringList newinfo;
352   if(!useronly){
353     QStringList sysfiles;  sysfiles << L_ETCDIR+"/lumina_environment.conf" << LOS::LuminaShare()+"lumina_environment.conf";
354     for(int i=0; i<sysfiles.length() && newinfo.isEmpty(); i++){
355       newinfo << LUtils::readFile(sysfiles[i]);
356     }
357   }
358   newinfo << LUtils::readFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf");
359   return newinfo;
360 }
361 
LoadCustomEnvSettings()362 void LTHEME::LoadCustomEnvSettings(){
363   //Also ensure that the normal XDG_* environment variables are setup (will not overwrite them if already there)
364   LXDG::setEnvironmentVars();
365   //will push the custom settings into the environment (recommended before loading the initial QApplication)
366   QStringList info = LTHEME::CustomEnvSettings(false); //all settings
367   if(info.isEmpty()){
368     //Ensure the file exists, and create it otherwise;
369     if(!QFile::exists( QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf")){
370       LUtils::writeFile( QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf", QStringList() << "", true);
371     }
372   }
373   for(int i=0; i<info.length(); i++){
374     if(info[i].isEmpty()){ continue; }
375     if(info[i].section("=",1,100).isEmpty()){
376       unsetenv(info[i].section("=",0,0).toLocal8Bit());
377     }else{
378       setenv(info[i].section("=",0,0).toLocal8Bit(), info[i].section("=",1,100).simplified().toLocal8Bit(), 1);
379     }
380   }
381 
382 }
383 
setCustomEnvSetting(QString var,QString val)384 bool LTHEME::setCustomEnvSetting(QString var, QString val){
385   //variable/value pair (use an empty val to clear it)
386   QStringList info = LTHEME::CustomEnvSettings(true); //user only
387   bool changed = false;
388   if(!info.filter(var+"=").isEmpty()){
389     for(int i=0; i<info.length(); i++){
390       //Make sure this is an exact variable match
391       if(!info[i].startsWith(var+"=")){ continue; }
392         //Found it - replace this line
393 	info[i] = var+"="+val;
394 	changed = true;
395     }
396   }
397   if(!changed){ info << var+"="+val; }
398   return LUtils::writeFile(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf", info, true);
399 }
400 
readCustomEnvSetting(QString var)401 QString LTHEME::readCustomEnvSetting(QString var){
402   QStringList info = LTHEME::CustomEnvSettings().filter(var+"=");
403   for(int i=info.length()-1; i>=0; i--){
404     if(info[i].startsWith(var+"=")){
405       return info[i].section("=",1,100).simplified();
406     }
407   }
408   //If it gets here, no setting found for that variable
409   return "";
410 }
411 
412 // =========================
413 //        LuminaThemeStyle
414 // =========================
415 /*LuminaThemeStyle::LuminaThemeStyle() : QProxyStyle(){
416   this->update();
417 }
418 
419 LuminaThemeStyle::~LuminaThemeStyle(){
420 
421 }
422 
423 //Function to update the style (for use by the theme engine)
424 void LuminaThemeStyle::update(){
425   darkfont = true; //make this dynamic later
426 }*/
427 
428 //Subclassed functions
429 //void LuminaThemeStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &palette, bool enabled, const QString &text, QPalette::ColorRole textRole) const{
430   /*QFont cfont = painter->font();
431     cfont.setHintingPreference(QFont::PreferFullHinting);
432   QFont outfont = cfont;
433     outfont.setStretch(101);
434     outfont.setLetterSpacing(QFont::PercentageSpacing, 99);
435   //Paint the background outline
436   if(darkfont){ painter->setPen(QPen(Qt::white)); }
437   else{ painter->setPen(QPen(Qt::black)); }
438   painter->setFont(outfont);
439   //QRect outline = QRect(rect.left()+2, rect.top()+2, rect.right()+2, rect.bottom()+2);
440   painter->drawText(rect, text);
441 
442   //Paint the text itself (Make this respect the "enabled" flag later)
443   painter->setFont(cfont);
444   if(darkfont){ painter->setPen(QPen(Qt::black)); }
445   else{ painter->setPen(QPen(Qt::white)); }
446   painter->drawText(rect, text);*/
447 
448   /*QFont font = painter->font();
449   QFont cfont = font; //save for later
450     if(font.pixelSize()>0){ font.setPixelSize( font.pixelSize()-4); }
451     else{ font.setPointSize(font.pointSize()-1); }
452   painter->setFont(font);
453   //Create the path
454   QPainterPath path;
455     //path.setFillRule(Qt::WindingFill);
456     path.addText(rect.left(), rect.center().y()+(painter->fontMetrics().xHeight()/2), painter->font(), text);
457   //Now set the border/fill colors
458   QPen pen;
459     pen.setWidth(2);
460     if(darkfont){
461       pen.setColor(Qt::white);
462       painter->fillPath(path,Qt::black);
463     }else{
464       pen.setColor(Qt::black);
465       painter->fillPath(path,Qt::white);
466     }
467   painter->setPen(pen);
468   painter->drawPath(path);
469   painter->setFont(cfont); //reset back to original font*/
470 
471 //}
472 
473 
474 //==================
475 //  THEME ENGINE CLASS
476 //==================
LuminaThemeEngine(QApplication * app)477 LuminaThemeEngine::LuminaThemeEngine(QApplication *app){
478   application=app; //save this pointer for later
479   //style = new LuminaThemeStyle();
480     //Set the application-wide style
481    //application->setStyle( style );
482 
483   lastcheck = QDateTime::currentDateTime(); //
484   // Now load the theme stylesheet
485   QStringList current = LTHEME::currentSettings();
486   theme = current[0]; colors=current[1]; icons=current[2]; font=current[3]; fontsize=current[4];
487   cursors = LTHEME::currentCursor();
488   if(application->applicationFilePath().section("/",-1)=="lumina-desktop"){
489     application->setStyleSheet( LTHEME::assembleStyleSheet(theme, colors, font, fontsize) );
490   }else{
491     //Non-Desktop binary - only use alternate Qt methods (skip stylesheets)
492     QFont tmp = application->font();
493     tmp.setStyleStrategy(QFont::PreferOutline);
494     tmp.setFamily(font);
495     tmp.setHintingPreference(QFont::PreferFullHinting);
496     if(fontsize.endsWith("pt")){ tmp.setPointSize(fontsize.section("pt",0,0).toInt()); }
497     else if(fontsize.endsWith("px")){ tmp.setPixelSize(fontsize.section("px",0,0).toInt()); }
498     application->setFont(tmp);
499   }
500   QIcon::setThemeName(icons); //make sure this sets set within this environment
501   syncTimer = new QTimer(this);
502     syncTimer->setSingleShot(true);
503     syncTimer->setInterval(500); //wait 1/2 second before re-loading the files
504   if(cursors.isEmpty()){
505     LTHEME::setCursorTheme("default"); //X11 fallback (always installed?)
506     cursors = "default";
507   }
508 
509   //setenv("XCURSOR_THEME", cursors.toLocal8Bit(),1);
510   watcher = new QFileSystemWatcher(this);
511 	watcher->addPath( QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf" );
512 	watcher->addPath( QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/themesettings.cfg" );
513 	watcher->addPaths( QStringList() << theme << colors << QDir::homePath()+"/.icons/default/index.theme" ); //also watch these files for changes
514   connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(watcherChange(QString)) );
515   connect(syncTimer, SIGNAL(timeout()), this, SLOT(reloadFiles()) );
516 }
517 
~LuminaThemeEngine()518 LuminaThemeEngine::~LuminaThemeEngine(){
519 
520 }
521 
refresh()522 void LuminaThemeEngine::refresh(){
523   QTimer::singleShot(100,this, SLOT(reloadFiles()) );
524 }
525 
watcherChange(QString file)526 void LuminaThemeEngine::watcherChange(QString file){
527   if(syncTimer->isActive()){ syncTimer->stop(); }
528   syncTimer->start();
529   if(!watcher->files().contains(file)){ watcher->addPath(file); }
530 }
531 
reloadFiles()532 void LuminaThemeEngine::reloadFiles(){
533   //Check the Theme file/settings
534   if(lastcheck < QFileInfo(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/themesettings.cfg").lastModified().addSecs(1) ){
535     QStringList current = LTHEME::currentSettings();
536     if(application->applicationFilePath().section("/",-1)=="lumina-desktop"){
537       application->setStyleSheet( LTHEME::assembleStyleSheet(current[0], current[1], current[3], current[4]) );
538     }
539     if(icons!=current[2]){
540       QIcon::setThemeName(current[2]); //make sure this sets set within this environment
541       emit updateIcons();
542     }
543     //save the settings for comparison later
544     theme = current[0]; colors=current[1]; icons=current[2];
545 
546     if(font!=current[3] || fontsize!=current[4]){
547       font=current[3]; fontsize=current[4];
548       QFont tmp = application->font();
549         tmp.setStyleStrategy(QFont::PreferAntialias);
550         tmp.setFamily(font);
551         if(fontsize.endsWith("pt")){ tmp.setPointSize(fontsize.section("pt",0,0).toInt()); }
552         else if(fontsize.endsWith("px")){ tmp.setPixelSize(fontsize.section("px",0,0).toInt()); }
553       application->setFont(tmp);
554     }
555   }
556   //Check the Cursor file/settings
557   if(lastcheck < QFileInfo(QDir::homePath()+"/.icons/default/index.theme").lastModified()){
558     QString ccurs = LTHEME::currentCursor();
559     if(cursors != ccurs){
560       emit updateCursors();
561       //Might be something we can do automatically here as well - since we have the QApplication handy
562       // - Note: setting/unsetting an override cursor does not update the current cursor bitmap
563       // Qt created a background database/hash/mapping of the theme pixmaps on startup
564       //   So Qt itself needs to be prodded to update that mapping
565       /*QXcbCursor::cursorThemePropertyChanged( \
566 	  new QXcbVirtualDesktop(QX11Info::connection(), application->screen()->handle(), QX11Info::appScreen()),
567 	  ccurs.toData(), QVariant("Inherits"), NULL);*/
568       //QCursorData::cleanup();
569       //QCursorData::initialize();
570       //setenv("XCURSOR_THEME", ccurs.toLocal8Bit(),1);
571     }
572     cursors = ccurs;
573   }
574 
575 
576   //Environment Changes
577   if( lastcheck < QFileInfo(QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf").lastModified()){
578     LTHEME::LoadCustomEnvSettings();
579     emit EnvChanged();
580   }
581   lastcheck = QDateTime::currentDateTime();
582 
583   //Now update the watched files to ensure nothing is missed
584   watcher->removePaths( QStringList() << theme << colors << QDir::homePath()+"/.icons/default/index.theme" << QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf");
585   watcher->addPaths( QStringList() << theme << colors << QDir::homePath()+"/.icons/default/index.theme" << QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/envsettings.conf");
586 }
587