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