MythTV  master
mythuihelper.cpp
Go to the documentation of this file.
1 #include "mythuihelper.h"
2 
3 #include <cmath>
4 #include <unistd.h>
5 
6 #include <QImage>
7 #include <QPixmap>
8 #include <QMutex>
9 #include <QPalette>
10 #include <QMap>
11 #include <QDir>
12 #include <QFileInfo>
13 #include <QApplication>
14 #include <QPainter>
15 #include <QStyleFactory>
16 #include <QSize>
17 #include <QFile>
18 #include <QAtomicInt>
19 #include <QEventLoop>
20 #include <QTimer>
21 #include <QScreen>
22 
23 // mythbase headers
24 #include "mythdirs.h"
25 #include "mythlogging.h"
26 #include "mythdownloadmanager.h"
27 #include "mythdb.h"
28 #include "remotefile.h"
29 #include "mythcorecontext.h"
30 #include "storagegroup.h"
31 #include "mythdate.h"
32 #include "mthreadpool.h"
33 
34 // mythui headers
35 #include "mythprogressdialog.h"
36 #include "mythimage.h"
37 #include "screensaver.h"
38 #include "mythmainwindow.h"
39 #include "themeinfo.h"
40 #include "x11colors.h"
41 #include "mythdisplay.h"
42 
43 #define LOC QString("MythUIHelper: ")
44 
45 static MythUIHelper *mythui = nullptr;
46 static QMutex uiLock;
48 
50 {
51  if (mythui)
52  return mythui;
53 
54  uiLock.lock();
55 
56  if (!mythui)
57  mythui = new MythUIHelper();
58 
59  uiLock.unlock();
60 
61  // These directories should always exist. Don't test first as
62  // there's no harm in trying to create an existing directory.
63  QDir dir;
64  dir.mkdir(GetThemeBaseCacheDir());
65  dir.mkdir(GetRemoteCacheDir());
66  dir.mkdir(GetThumbnailDir());
67 
68  return mythui;
69 }
70 
72 {
75  uiLock.lock();
76  delete mythui;
77  mythui = nullptr;
78  uiLock.unlock();
79 }
80 
82 {
83  return MythUIHelper::getMythUI();
84 }
85 
87 {
89 }
90 
92 {
93 public:
95  : m_cacheLock(new QMutex(QMutex::Recursive)),
96  m_imageThreadPool(new MThreadPool("MythUIHelper")),
97  m_parent(p) {}
99 
100  void Init();
101  void StoreGUIsettings(void);
102 
103  bool m_themeloaded {false};
106  QString m_themename;
107  QPalette m_palette;
108 
109  float m_wmult {1.0F};
110  float m_hmult {1.0F};
111 
112  // Dimensions of the theme
113  QSize m_baseSize { 800, 600 };
114  bool m_isWide {false};
115 
116  QMap<QString, MythImage *> m_imageCache;
117 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
118  QMap<QString, uint> m_cacheTrack;
119 #else
120  QMap<QString, qint64> m_cacheTrack;
121 #endif
122  QMutex *m_cacheLock {nullptr};
123 
124 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
125  QAtomicInt m_cacheSize {0};
126  QAtomicInt m_maxCacheSize {30 * 1024 * 1024};
127 #else
128  // This change is because of the QImage change from byteCount() to
129  // sizeInBytes(), the latter returning a 64bit value.
130  QAtomicInteger<qint64> m_cacheSize {0};
131  QAtomicInteger<qint64> m_maxCacheSize {30 * 1024 * 1024};
132 #endif
133 
134  // The part of the screen(s) allocated for the GUI. Unless
135  // overridden by the user, defaults to the full drawable area.
136  QRect m_screenRect { 0, 0, 0, 0};
137 
138  // Command-line GUI size, which overrides both the above sets of sizes
139  static int x_override;
140  static int y_override;
141  static int w_override;
142  static int h_override;
143 
145  QString m_userThemeDir;
146 
148  bool m_screensaverEnabled {false};
149 
150  MythDisplay *m_display {nullptr};
151  bool m_screenSetup {false};
152 
154 
155  MythUIMenuCallbacks m_callbacks {nullptr,nullptr,nullptr,nullptr,nullptr};
156 
157  MythUIHelper *m_parent {nullptr};
158 
159  int m_fontStretch {100};
160 
161  QStringList m_searchPaths;
162 };
163 
168 
170 {
171  QMutableMapIterator<QString, MythImage *> i(m_imageCache);
172 
173  while (i.hasNext())
174  {
175  i.next();
176  i.value()->SetIsInCache(false);
177  i.value()->DecrRef();
178  i.remove();
179  }
180 
181  m_cacheTrack.clear();
182 
183  delete m_cacheLock;
184  delete m_imageThreadPool;
185  delete m_screensaver;
186 
187  if (m_display)
188  {
189  // N.B. we always call this to ensure the desktop mode is restored
190  // in case the setting was changed
193  }
194 }
195 
197 {
198  if (!m_display)
202  m_screenSetup = true;
203 
204  StorageGroup sgroup("Themes", gCoreContext->GetHostName());
205  m_userThemeDir = sgroup.GetFirstDir(true);
206 }
207 
212 {
213  if (x_override >= 0 && y_override >= 0)
214  {
215  GetMythDB()->OverrideSettingForSession("GuiOffsetX", QString::number(x_override));
216  GetMythDB()->OverrideSettingForSession("GuiOffsetY", QString::number(y_override));
217  }
218 
219  if (w_override > 0 && h_override > 0)
220  {
221  GetMythDB()->OverrideSettingForSession("GuiWidth", QString::number(w_override));
222  GetMythDB()->OverrideSettingForSession("GuiHeight", QString::number(h_override));
223  }
224 
225  int x = GetMythDB()->GetNumSetting("GuiOffsetX");
226  int y = GetMythDB()->GetNumSetting("GuiOffsetY");
227  int width = 0;
228  int height = 0;
229  GetMythDB()->GetResolutionSetting("Gui", width, height);
230 
231  if (!m_display)
233  QRect screenbounds = m_display->GetScreenBounds();
234 
235  // As per MythMainWindow::Init, fullscreen is indicated by all zero's in settings
236  if (x == 0 && y == 0 && width == 0 && height == 0)
237  m_screenRect = screenbounds;
238  else
239  m_screenRect = QRect(x, y, width, height);
240 
241  if (m_screenRect.width() < 160 || m_screenRect.height() < 160)
242  {
243  LOG(VB_GENERAL, LOG_ERR, LOC +
244  "Somehow, your screen size settings are bad.\n\t\t\t" +
245  QString("GuiResolution: %1\n\t\t\t")
246  .arg(GetMythDB()->GetSetting("GuiResolution")) +
247  QString(" old GuiWidth: %1\n\t\t\t")
248  .arg(GetMythDB()->GetNumSetting("GuiWidth")) +
249  QString(" old GuiHeight: %1\n\t\t\t")
250  .arg(GetMythDB()->GetNumSetting("GuiHeight")) +
251  QString("width: %1 ").arg(m_screenRect.width()) +
252  QString("height: %1\n\t\t\t").arg(m_screenRect.height()) +
253  "Falling back to 640x480");
254  m_screenRect.setSize(QSize(640, 480));
255  }
256 
257  m_wmult = m_screenRect.width() / static_cast<float>(m_baseSize.width());
258  m_hmult = m_screenRect.height() / static_cast<float>(m_baseSize.height());
259 
260  // Default font, _ALL_ fonts inherit from this!
261  // e.g All fonts will be 19 pixels unless a new size is explicitly defined.
262  QFont font = QFont("Arial");
263 
264  if (!font.exactMatch())
265  font = QFont();
266 
267  font.setStyleHint(QFont::SansSerif, QFont::PreferAntialias);
268  font.setPixelSize(static_cast<int>(lroundf(19.0F * m_hmult)));
269  int stretch = static_cast<int>(100 / m_display->GetPixelAspectRatio());
270  font.setStretch(stretch); // QT
271  m_fontStretch = stretch; // MythUI
272 
273  QApplication::setFont(font);
274 }
275 
277 {
278  d = new MythUIHelperPrivate(this);
279 }
280 
282 {
283  delete d;
284 }
285 
287 {
288  d->Init();
289  d->m_callbacks = cbs;
290 
291  d->m_maxCacheSize.fetchAndStoreRelease(
292  GetMythDB()->GetNumSetting("UIImageCacheSize", 30) * 1024 * 1024);
293 
294  LOG(VB_GUI, LOG_INFO, LOC +
295  QString("MythUI Image Cache size set to %1 bytes")
296  .arg(d->m_maxCacheSize.fetchAndAddRelease(0)));
297 }
298 
299 // This init is used for showing the startup UI that is shown
300 // before the database is initialized. The above init is called later,
301 // after the DB is available.
302 // This class does not mind being Initialized twice.
304 {
305  d->Init();
306 }
307 
309 {
310  return &(d->m_callbacks);
311 }
312 
314 {
315  return d->m_screenSetup;
316 }
317 
319 {
321 }
322 
324 {
326  d->m_themecachedir.clear();
327 
328  if (!d->m_display)
330 
331  // Switch to desired GUI resolution
332  if (d->m_display->UsingVideoModes())
333  d->m_display->SwitchToGUI(true);
334 
335  qApp->setStyle("Windows");
336 
337  QString themename = GetMythDB()->GetSetting("Theme", DEFAULT_UI_THEME);
338  QString themedir = FindThemeDir(themename);
339 
340  auto *themeinfo = new ThemeInfo(themedir);
341  if (themeinfo)
342  {
343  d->m_isWide = themeinfo->IsWide();
344  d->m_baseSize = themeinfo->GetBaseRes();
345  d->m_themename = themeinfo->GetName();
346  LOG(VB_GUI, LOG_INFO, LOC +
347  QString("Using theme base resolution of %1x%2")
348  .arg(d->m_baseSize.width()).arg(d->m_baseSize.height()));
349  delete themeinfo;
350  }
351 
352  // Recalculate GUI dimensions
353  d->StoreGUIsettings();
354 
355  d->m_themepathname = themedir + '/';
356  d->m_searchPaths.clear();
357 
358  d->m_themeloaded = false;
359 
360  themename = GetMythDB()->GetSetting("MenuTheme", "defaultmenu");
361 
362  if (themename == "default")
363  themename = "defaultmenu";
364 
365  d->m_menuthemepathname = FindMenuThemeDir(themename);
366 }
367 
369 {
370  QMutexLocker locker(d->m_cacheLock);
371 
372  QMutableMapIterator<QString, MythImage *> i(d->m_imageCache);
373 
374  while (i.hasNext())
375  {
376  i.next();
377  i.value()->SetIsInCache(false);
378  i.value()->DecrRef();
379  i.remove();
380  }
381 
382  d->m_cacheTrack.clear();
383 
384  d->m_cacheSize.fetchAndStoreOrdered(0);
385 
389 }
390 
392 {
393  QMutexLocker locker(d->m_cacheLock);
394 
395  if (d->m_imageCache.contains(url))
396  {
397 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
398  d->m_cacheTrack[url] = MythDate::current().toTime_t();
399 #else
400  d->m_cacheTrack[url] = MythDate::current().toSecsSinceEpoch();
401 #endif
402  d->m_imageCache[url]->IncrRef();
403  return d->m_imageCache[url];
404  }
405 
406  /*
407  if (QFileInfo(url).exists())
408  {
409  MythImage *im = GetMythPainter()->GetFormatImage();
410  im->Load(url,false);
411  return im;
412  }
413  */
414 
415  return nullptr;
416 }
417 
419 {
420  if (im)
421  {
422 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
423  d->m_cacheSize.fetchAndAddOrdered(im->byteCount());
424 #else
425  d->m_cacheSize.fetchAndAddOrdered(im->sizeInBytes());
426 #endif
427  }
428 }
429 
431 {
432  if (im)
433  {
434 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
435  d->m_cacheSize.fetchAndAddOrdered(-im->byteCount());
436 #else
437  d->m_cacheSize.fetchAndAddOrdered(-im->sizeInBytes());
438 #endif
439  }
440 }
441 
443  bool nodisk)
444 {
445  if (!im)
446  return nullptr;
447 
448  if (!nodisk)
449  {
450  QString dstfile = GetCacheDirByUrl(url) + '/' + url;
451 
452  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
453  QString("Saved to Cache (%1)").arg(dstfile));
454 
455  // Save to disk cache
456  im->save(dstfile, "PNG");
457  }
458 
459  // delete the oldest cached images until we fall below threshold.
460  QMutexLocker locker(d->m_cacheLock);
461 
462  while ((d->m_cacheSize.fetchAndAddOrdered(0) +
463 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
464  im->byteCount()
465 #else
466  im->sizeInBytes()
467 #endif
468  ) >=
469  d->m_maxCacheSize.fetchAndAddOrdered(0) &&
470  !d->m_imageCache.empty())
471  {
472  QMap<QString, MythImage *>::iterator it = d->m_imageCache.begin();
473 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
474  uint oldestTime = MythDate::current().toTime_t();
475 #else
476  qint64 oldestTime = MythDate::current().toSecsSinceEpoch();
477 #endif
478  QString oldestKey = it.key();
479 
480  int count = 0;
481 
482  for (; it != d->m_imageCache.end(); ++it)
483  {
484  if (d->m_cacheTrack[it.key()] < oldestTime)
485  {
486  if ((2 == it.value()->IncrRef()) && (it.value() != im))
487  {
488  oldestTime = d->m_cacheTrack[it.key()];
489  oldestKey = it.key();
490  count++;
491  }
492  it.value()->DecrRef();
493  }
494  }
495 
496  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
497  QString("%1 images are eligible for expiry").arg(count));
498 
499  if (count > 0)
500  {
501  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
502  QString("Cache too big (%1), removing :%2:")
503  .arg(d->m_cacheSize.fetchAndAddOrdered(0) +
504 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
505  im->byteCount()
506 #else
507  im->sizeInBytes()
508 #endif
509  )
510  .arg(oldestKey));
511 
512  d->m_imageCache[oldestKey]->SetIsInCache(false);
513  d->m_imageCache[oldestKey]->DecrRef();
514  d->m_imageCache.remove(oldestKey);
515  d->m_cacheTrack.remove(oldestKey);
516  }
517  else
518  {
519  break;
520  }
521  }
522 
523  QMap<QString, MythImage *>::iterator it = d->m_imageCache.find(url);
524 
525  if (it == d->m_imageCache.end())
526  {
527  im->IncrRef();
528  d->m_imageCache[url] = im;
529 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
530  d->m_cacheTrack[url] = MythDate::current().toTime_t();
531 #else
532  d->m_cacheTrack[url] = MythDate::current().toSecsSinceEpoch();
533 #endif
534 
535  im->SetIsInCache(true);
536  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
537  QString("NOT IN RAM CACHE, Adding, and adding to size :%1: :%2:")
538  .arg(url)
539 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
540  .arg(im->byteCount())
541 #else
542  .arg(im->sizeInBytes())
543 #endif
544  );
545  }
546 
547  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
548  QString("MythUIHelper::CacheImage : Cache Count = :%1: size :%2:")
549  .arg(d->m_imageCache.count())
550  .arg(d->m_cacheSize.fetchAndAddRelaxed(0)));
551 
552  return d->m_imageCache[url];
553 }
554 
555 void MythUIHelper::RemoveFromCacheByURL(const QString &url)
556 {
557  QMutexLocker locker(d->m_cacheLock);
558  QMap<QString, MythImage *>::iterator it = d->m_imageCache.find(url);
559 
560  if (it != d->m_imageCache.end())
561  {
562  d->m_imageCache[url]->SetIsInCache(false);
563  d->m_imageCache[url]->DecrRef();
564  d->m_imageCache.remove(url);
565  d->m_cacheTrack.remove(url);
566  }
567 
568  QString dstfile;
569 
570  dstfile = GetCacheDirByUrl(url) + '/' + url;
571  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
572  QString("RemoveFromCacheByURL removed :%1: from cache").arg(dstfile));
573  QFile::remove(dstfile);
574 }
575 
576 void MythUIHelper::RemoveFromCacheByFile(const QString &fname)
577 {
578  QList<QString>::iterator it;
579 
580  QString partialKey = fname;
581  partialKey.replace('/', '-');
582 
583  d->m_cacheLock->lock();
584  QList<QString> m_imageCacheKeys = d->m_imageCache.keys();
585  d->m_cacheLock->unlock();
586 
587  for (it = m_imageCacheKeys.begin(); it != m_imageCacheKeys.end(); ++it)
588  {
589  if ((*it).contains(partialKey))
591  }
592 
593  // Loop through files to cache any that were not caught by
594  // RemoveFromCacheByURL
595  QDir dir(GetThemeCacheDir());
596  QFileInfoList list = dir.entryInfoList();
597 
598  for (const auto & fileInfo : list)
599  {
600  if (fileInfo.fileName().contains(partialKey))
601  {
602  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
603  QString("RemoveFromCacheByFile removed: %1: from cache")
604  .arg(fileInfo.fileName()));
605 
606  if (!dir.remove(fileInfo.fileName()))
607  {
608  LOG(VB_GENERAL, LOG_ERR, LOC +
609  QString("Failed to delete %1 from the theme cache")
610  .arg(fileInfo.fileName()));
611  }
612  }
613  }
614 }
615 
616 bool MythUIHelper::IsImageInCache(const QString &url)
617 {
618  QMutexLocker locker(d->m_cacheLock);
619 
620  if (d->m_imageCache.contains(url))
621  return true;
622 
623  if (QFileInfo(url).exists())
624  return true;
625 
626  return false;
627 }
628 
630 {
631  static QString s_oldcachedir;
632  QString tmpcachedir = GetThemeBaseCacheDir() + "/" +
633  GetMythDB()->GetSetting("Theme", DEFAULT_UI_THEME) +
634  "." + QString::number(d->m_screenRect.width()) +
635  "." + QString::number(d->m_screenRect.height());
636 
637  if (tmpcachedir != s_oldcachedir)
638  {
639  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
640  QString("Creating cache dir: %1").arg(tmpcachedir));
641  QDir dir;
642  dir.mkdir(tmpcachedir);
643  s_oldcachedir = tmpcachedir;
644  }
645  return tmpcachedir;
646 }
647 
655 QString MythUIHelper::GetCacheDirByUrl(const QString& url)
656 {
657  if (url.startsWith("myth:") || url.startsWith("-"))
658  return GetThumbnailDir();
659  return GetThemeCacheDir();
660 }
661 
663 {
665 
666  QString themecachedir = d->m_themecachedir;
667 
668  d->m_themecachedir += '/';
669 
670  QDir dir(GetThemeBaseCacheDir());
671  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
672  QFileInfoList list = dir.entryInfoList();
673 
674  QFileInfoList::const_iterator it = list.begin();
675  QMap<QDateTime, QString> dirtimes;
676 
677  while (it != list.end())
678  {
679  const QFileInfo *fi = &(*it++);
680 
681  if (fi->isDir() && !fi->isSymLink())
682  {
683  if (fi->absoluteFilePath() == themecachedir)
684  continue;
685 
686  dirtimes[fi->lastModified()] = fi->absoluteFilePath();
687  }
688  }
689 
690  // Cache two themes/resolutions to allow sampling other themes without
691  // incurring a penalty. Especially for those writing new themes or testing
692  // changes of an existing theme. The space used is neglible when compared
693  // against the average video
694  while ((size_t)dirtimes.size() >= 2)
695  {
696  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC + QString("Removing cache dir: %1")
697  .arg(dirtimes.begin().value()));
698 
699  RemoveCacheDir(dirtimes.begin().value());
700  dirtimes.erase(dirtimes.begin());
701  }
702 
703  foreach (const auto & dirtime, dirtimes)
704  {
705  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
706  QString("Keeping cache dir: %1").arg(dirtime));
707  }
708 }
709 
710 void MythUIHelper::RemoveCacheDir(const QString &dirname)
711 {
712  QString cachedirname = GetThemeBaseCacheDir();
713 
714  if (!dirname.startsWith(cachedirname))
715  return;
716 
717  LOG(VB_GENERAL, LOG_ERR, LOC +
718  QString("Removing stale cache dir: %1").arg(dirname));
719 
720  QDir dir(dirname);
721 
722  if (!dir.exists())
723  return;
724 
725  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
726  QFileInfoList list = dir.entryInfoList();
727  QFileInfoList::const_iterator it = list.begin();
728 
729  while (it != list.end())
730  {
731  const QFileInfo *fi = &(*it++);
732 
733  if (fi->isFile() && !fi->isSymLink())
734  {
735  QFile file(fi->absoluteFilePath());
736  file.remove();
737  }
738  else if (fi->isDir() && !fi->isSymLink())
739  {
740  RemoveCacheDir(fi->absoluteFilePath());
741  }
742  }
743 
744  dir.rmdir(dirname);
745 }
746 
753 void MythUIHelper::PruneCacheDir(const QString& dirname)
754 {
755  int days = GetMythDB()->GetNumSetting("UIDiskCacheDays", 7);
756  if (days == -1) {
757  LOG(VB_GENERAL, LOG_INFO, LOC +
758  QString("Pruning cache directory: %1 is disabled").arg(dirname));
759  return;
760  }
761 
762  LOG(VB_GENERAL, LOG_INFO, LOC +
763  QString("Pruning cache directory: %1").arg(dirname));
764  QDateTime cutoff = MythDate::current().addDays(-days);
765 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
766  qint64 cutoffsecs = cutoff.toMSecsSinceEpoch()/1000;
767 #else
768  qint64 cutoffsecs = cutoff.toSecsSinceEpoch();
769 #endif
770 
771  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
772  QString("Removing files not accessed since %1")
773  .arg(cutoff.toLocalTime().toString(Qt::ISODate)));
774 
775  int kept = 0;
776  int deleted = 0;
777  int errcnt = 0;
778  QDir dir(dirname);
779  dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
780  dir.setSorting(QDir::NoSort);
781 
782  // Trying to save every cycle possible within this loop. The
783  // stat() call seems significantly faster than the fi.fileRead()
784  // method. The documentation for QFileInfo says that the
785  // fi.absoluteFilePath() method has to query the file system, so
786  // use fi.filePath() method here and then add the directory if
787  // needed. Using dir.entryList() and adding the dirname each time
788  // is also slower just using dir.entryInfoList().
789  foreach (const QFileInfo &fi, dir.entryInfoList())
790  {
791  struct stat buf {};
792  QString fullname = fi.filePath();
793  if (not fullname.startsWith('/'))
794  fullname = dirname + "/" + fullname;
795  QByteArray fullname8 = fullname.toLocal8Bit();
796  int rc = stat(fullname8, &buf);
797  if (rc == -1)
798  {
799  errcnt += 1;
800  continue;
801  }
802  if (buf.st_atime >= cutoffsecs)
803  {
804  kept += 1;
805  LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
806  QString("%1 Keep %2")
807  .arg(fi.lastRead().toLocalTime().toString(Qt::ISODate))
808  .arg(fi.fileName()));
809  continue;
810  }
811  deleted += 1;
812  LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
813  QString("%1 Delete %2")
814  .arg(fi.lastRead().toLocalTime().toString(Qt::ISODate))
815  .arg(fi.fileName()));
816  unlink(fullname8);
817  }
818 
819  LOG(VB_GENERAL, LOG_INFO, LOC +
820  QString("Kept %1 files, deleted %2 files, stat error on %3 files")
821  .arg(kept).arg(deleted).arg(errcnt));
822 }
823 
825 {
826  d->StoreGUIsettings();
827 }
828 
830 {
831  return d->m_screenRect;
832 }
833 
834 void MythUIHelper::GetScreenSettings(float &XFactor, float &YFactor)
835 {
836  XFactor = d->m_wmult;
837  YFactor = d->m_hmult;
838 }
839 
840 void MythUIHelper::GetScreenSettings(QRect &Rect, float &XFactor, float &YFactor)
841 {
842  XFactor = d->m_wmult;
843  YFactor = d->m_hmult;
844  Rect = d->m_screenRect;
845 }
846 
856 void MythUIHelper::ParseGeometryOverride(const QString &geometry)
857 {
858  QRegExp sre("^(\\d+)x(\\d+)$");
859  QRegExp lre("^(\\d+)x(\\d+)([+-]\\d+)([+-]\\d+)$");
860  QStringList geo;
861  bool longForm = false;
862 
863  if (sre.exactMatch(geometry))
864  {
865  geo = sre.capturedTexts();
866  }
867  else if (lre.exactMatch(geometry))
868  {
869  geo = lre.capturedTexts();
870  longForm = true;
871  }
872  else
873  {
874  LOG(VB_GENERAL, LOG_ERR, LOC +
875  "Geometry does not match either form -\n\t\t\t"
876  "WIDTHxHEIGHT or WIDTHxHEIGHT+XOFF+YOFF");
877  return;
878  }
879 
880  bool parsed = false;
881  int tmp_h = 0;
882  int tmp_w = geo[1].toInt(&parsed);
883 
884  if (!parsed)
885  {
886  LOG(VB_GENERAL, LOG_ERR, LOC +
887  "Could not parse width of geometry override");
888  }
889 
890  if (parsed)
891  {
892  tmp_h = geo[2].toInt(&parsed);
893 
894  if (!parsed)
895  {
896  LOG(VB_GENERAL, LOG_ERR, LOC +
897  "Could not parse height of geometry override");
898  }
899  }
900 
901  if (parsed)
902  {
905  LOG(VB_GENERAL, LOG_INFO, LOC +
906  QString("Overriding GUI size: width=%1 height=%2")
907  .arg(tmp_w).arg(tmp_h));
908  }
909  else
910  {
911  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to override GUI size.");
912  }
913 
914  if (longForm)
915  {
916  int tmp_x = geo[3].toInt(&parsed);
917  if (!parsed)
918  {
919  LOG(VB_GENERAL, LOG_ERR, LOC +
920  "Could not parse horizontal offset of geometry override");
921  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to override GUI offset.");
922  return;
923  }
924 
925  int tmp_y = geo[4].toInt(&parsed);
926  if (!parsed)
927  {
928  LOG(VB_GENERAL, LOG_ERR, LOC +
929  "Could not parse vertical offset of geometry override");
930  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to override GUI offset.");
931  return;
932  }
933 
936  LOG(VB_GENERAL, LOG_INFO, LOC +
937  QString("Overriding GUI offset: x=%1 y=%2")
938  .arg(tmp_x).arg(tmp_y));
939  }
940 }
941 
943 {
944  return (MythUIHelperPrivate::x_override >= 0 ||
948 }
949 
956 {
957  // NB Call IsGeometryOverridden first to ensure this is valid
960 }
961 
973 QString MythUIHelper::FindThemeDir(const QString &themename, bool doFallback)
974 {
975  QString testdir;
976  QDir dir;
977 
978  if (!themename.isEmpty())
979  {
980  testdir = d->m_userThemeDir + themename;
981 
982  dir.setPath(testdir);
983 
984  if (dir.exists())
985  return testdir;
986 
987  testdir = GetThemesParentDir() + themename;
988  dir.setPath(testdir);
989 
990  if (dir.exists())
991  return testdir;
992 
993  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No theme dir: '%1'")
994  .arg(dir.absolutePath()));
995  }
996 
997  if (!doFallback)
998  return QString();
999 
1000  testdir = GetThemesParentDir() + DEFAULT_UI_THEME;
1001  dir.setPath(testdir);
1002 
1003  if (dir.exists())
1004  {
1005  LOG(VB_GENERAL, LOG_ERR, LOC +
1006  QString("Could not find theme: %1 - Switching to %2")
1007  .arg(themename).arg(DEFAULT_UI_THEME));
1008  GetMythDB()->OverrideSettingForSession("Theme", DEFAULT_UI_THEME);
1009  return testdir;
1010  }
1011 
1012  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No default theme dir: '%1'")
1013  .arg(dir.absolutePath()));
1014 
1015  testdir = GetThemesParentDir() + FALLBACK_UI_THEME;
1016  dir.setPath(testdir);
1017 
1018  if (dir.exists())
1019  {
1020  LOG(VB_GENERAL, LOG_ERR, LOC +
1021  QString("Could not find theme: %1 - Switching to %2")
1022  .arg(themename).arg(FALLBACK_UI_THEME));
1023  GetMythDB()->OverrideSettingForSession("Theme", FALLBACK_UI_THEME);
1024  return testdir;
1025  }
1026 
1027  LOG(VB_GENERAL, LOG_ERR, LOC + QString("No fallback GUI theme dir: '%1'")
1028  .arg(dir.absolutePath()));
1029 
1030  return QString();
1031 }
1032 
1041 QString MythUIHelper::FindMenuThemeDir(const QString &menuname)
1042 {
1043  QString testdir;
1044  QDir dir;
1045 
1046  testdir = d->m_userThemeDir + menuname;
1047 
1048  dir.setPath(testdir);
1049 
1050  if (dir.exists())
1051  return testdir;
1052 
1053  testdir = GetThemesParentDir() + menuname;
1054  dir.setPath(testdir);
1055 
1056  if (dir.exists())
1057  return testdir;
1058 
1059  testdir = GetShareDir();
1060  dir.setPath(testdir);
1061 
1062  if (dir.exists())
1063  {
1064  LOG(VB_GENERAL, LOG_ERR, LOC +
1065  QString("Could not find menu theme: %1 - Switching to default")
1066  .arg(menuname));
1067 
1068  GetMythDB()->SaveSetting("MenuTheme", "default");
1069  return testdir;
1070  }
1071 
1072  LOG(VB_GENERAL, LOG_ERR, LOC +
1073  QString("Could not find menu theme: %1 - Fallback to default failed.")
1074  .arg(menuname));
1075 
1076  return QString();
1077 }
1078 
1080 {
1081  return d->m_menuthemepathname;
1082 }
1083 
1085 {
1086  return d->m_themepathname;
1087 }
1088 
1090 {
1091  return d->m_themename;
1092 }
1093 
1095 {
1096  if (!d->m_searchPaths.isEmpty())
1097  return d->m_searchPaths;
1098 
1099  // traverse up the theme inheritance list adding their location to the search path
1100  QList<ThemeInfo> themeList = GetThemes(THEME_UI);
1101  bool found = true;
1102  QString themeName = d->m_themename;
1103  QString baseName;
1104  QString dirName;
1105 
1106  while (found && !themeName.isEmpty())
1107  {
1108  // find the ThemeInfo for this theme
1109  found = false;
1110  baseName = "";
1111  dirName = "";
1112 
1113  for (int x = 0; x < themeList.count(); x++)
1114  {
1115  if (themeList.at(x).GetName() == themeName)
1116  {
1117  found = true;
1118  baseName = themeList.at(x).GetBaseTheme();
1119  dirName = themeList.at(x).GetDirectoryName();
1120  break;
1121  }
1122  }
1123 
1124  // try to find where the theme is installed
1125  if (found)
1126  {
1127  QString themedir = FindThemeDir(dirName, false);
1128  if (!themedir.isEmpty())
1129  {
1130  LOG(VB_GUI, LOG_INFO, LOC + QString("Adding path '%1' to theme search paths").arg(themedir));
1131  d->m_searchPaths.append(themedir + '/');
1132  }
1133  else
1134  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Could not find ui theme location: %1").arg(themedir));
1135  }
1136  else
1137  {
1138  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Could not find inherited theme: %1").arg(themeName));
1139  }
1140 
1141  themeName = baseName;
1142  }
1143 
1144  if (d->m_isWide)
1145  d->m_searchPaths.append(GetThemesParentDir() + "default-wide/");
1146 
1147  d->m_searchPaths.append(GetThemesParentDir() + "default/");
1148  d->m_searchPaths.append("/tmp/");
1149  return d->m_searchPaths;
1150 }
1151 
1153 {
1154  QFileInfoList fileList;
1155  QList<ThemeInfo> themeList;
1156  QDir themeDirs(GetThemesParentDir());
1157  themeDirs.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1158  themeDirs.setSorting(QDir::Name | QDir::IgnoreCase);
1159 
1160  fileList.append(themeDirs.entryInfoList());
1161 
1162  themeDirs.setPath(d->m_userThemeDir);
1163 
1164  fileList.append(themeDirs.entryInfoList());
1165 
1166  foreach (auto & theme, fileList)
1167  {
1168  if (theme.baseName() == "default" ||
1169  theme.baseName() == "default-wide" ||
1170  theme.baseName() == "Slave")
1171  continue;
1172 
1173  ThemeInfo themeInfo(theme.absoluteFilePath());
1174 
1175  if (themeInfo.GetType() & type)
1176  themeList.append(themeInfo);
1177  }
1178 
1179  return themeList;
1180 }
1181 
1182 bool MythUIHelper::FindThemeFile(QString &path)
1183 {
1184  QFileInfo fi(path);
1185 
1186  if (fi.isAbsolute() && fi.exists())
1187  return true;
1188 #ifdef Q_OS_ANDROID
1189  if (path.startsWith("assets:/") && fi.exists())
1190  return true;
1191 #endif
1192 
1193  QString file;
1194  bool foundit = false;
1195  const QStringList searchpath = GetThemeSearchPath();
1196 
1197  foreach (const auto & ii, searchpath)
1198  {
1199  if (fi.isRelative())
1200  {
1201  file = ii + fi.filePath();
1202  }
1203  else if (fi.isAbsolute() && !fi.isRoot())
1204  {
1205  file = ii + fi.fileName();
1206  }
1207 
1208  if (QFile::exists(file))
1209  {
1210  path = file;
1211  foundit = true;
1212  break;
1213  }
1214  }
1215 
1216  return foundit;
1217 }
1218 
1219 MythImage *MythUIHelper::LoadCacheImage(QString srcfile, const QString& label,
1220  MythPainter *painter,
1221  ImageCacheMode cacheMode)
1222 {
1223  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
1224  QString("LoadCacheImage(%1,%2)").arg(srcfile).arg(label));
1225 
1226  if (srcfile.isEmpty() || label.isEmpty())
1227  return nullptr;
1228 
1229  if (!(kCacheForceStat & cacheMode))
1230  {
1231  // Some screens include certain images dozens or even hundreds of
1232  // times. Even if the image is in the cache, there is still a
1233  // stat system call on the original file to see if it has changed.
1234  // This code relaxes the original-file check so that the check
1235  // isn't repeated if it was already done within kImageCacheTimeout
1236  // seconds.
1237 
1238  // This only applies to the MEMORY cache
1239  const uint kImageCacheTimeout = 60;
1240 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
1241  uint now = MythDate::current().toTime_t();
1242 #else
1243  qint64 now = MythDate::current().toSecsSinceEpoch();
1244 #endif
1245 
1246  QMutexLocker locker(d->m_cacheLock);
1247 
1248  if (d->m_imageCache.contains(label) &&
1249  d->m_cacheTrack[label] + kImageCacheTimeout > now)
1250  {
1251  d->m_imageCache[label]->IncrRef();
1252  return d->m_imageCache[label];
1253  }
1254  }
1255 
1256  MythImage *ret = nullptr;
1257 
1258  // Check Memory Cache
1259  ret = GetImageFromCache(label);
1260 
1261  // If the image is in the memory or we are not ignoring the disk cache
1262  // then proceed to check whether the source file is newer than our cached
1263  // copy
1264  if (ret || !(cacheMode & kCacheIgnoreDisk))
1265  {
1266  // Create url to image in disk cache
1267  QString cachefilepath;
1268  cachefilepath = GetCacheDirByUrl(label) + '/' + label;
1269  QFileInfo cacheFileInfo(cachefilepath);
1270 
1271  // If the file isn't in the disk cache, then we don't want to bother
1272  // checking the last modified times of the original
1273  if (!cacheFileInfo.exists())
1274  return nullptr;
1275 
1276  // Now compare the time on the source versus our cached copy
1277  QDateTime srcLastModified;
1278 
1279  // For internet images this involves querying the headers of the remote
1280  // image. This is slow even without redownloading the whole image
1281  if ((srcfile.startsWith("http://")) ||
1282  (srcfile.startsWith("https://")) ||
1283  (srcfile.startsWith("ftp://")))
1284  {
1285  // If the image is in the memory cache then skip the last modified
1286  // check, since memory cached images are loaded in the foreground
1287  // this can cause an intolerable delay. The images won't stay in
1288  // the cache forever and so eventually they will be checked.
1289  if (ret)
1290  srcLastModified = cacheFileInfo.lastModified();
1291  else
1292  {
1293  srcLastModified =
1295  }
1296  }
1297  else if (srcfile.startsWith("myth://"))
1298  srcLastModified = RemoteFile::LastModified(srcfile);
1299  else
1300  {
1301  if (!FindThemeFile(srcfile))
1302  return nullptr;
1303 
1304  QFileInfo original(srcfile);
1305 
1306  if (original.exists())
1307  srcLastModified = original.lastModified();
1308  }
1309 
1310  // Now compare the timestamps, if the cached image is newer than the
1311  // source image we can use it, otherwise we want to remove it from the
1312  // cache
1313  if (cacheFileInfo.lastModified() >= srcLastModified)
1314  {
1315  // If we haven't already loaded the image from the memory cache
1316  // and we're not ignoring the disk cache, then it's time to load
1317  // it from there instead
1318  if (!ret && (cacheMode == kCacheNormal))
1319  {
1320 
1321  if (painter)
1322  {
1323  ret = painter->GetFormatImage();
1324 
1325  // Load file from disk cache to memory cache
1326  if (ret->Load(cachefilepath))
1327  {
1328  // Add to ram cache, and skip saving to disk since that is
1329  // where we found this in the first place.
1330  CacheImage(label, ret, true);
1331  }
1332  else
1333  {
1334  LOG(VB_GUI | VB_FILE, LOG_WARNING, LOC +
1335  QString("LoadCacheImage: Could not load :%1")
1336  .arg(cachefilepath));
1337 
1338  ret->SetIsInCache(false);
1339  ret->DecrRef();
1340  ret = nullptr;
1341  }
1342  }
1343  }
1344  }
1345  else
1346  {
1347  ret = nullptr;
1348  // If file has changed on disk, then remove it from the memory
1349  // and disk cache
1350  RemoveFromCacheByURL(label);
1351  }
1352  }
1353 
1354  return ret;
1355 }
1356 
1358 {
1359  QFont font = QApplication::font();
1360  font.setPointSize(GetMythMainWindow()->NormalizeFontSize(25));
1361  font.setWeight(QFont::Bold);
1362 
1363  return font;
1364 }
1365 
1367 {
1368  QFont font = QApplication::font();
1369  font.setPointSize(GetMythMainWindow()->NormalizeFontSize(16));
1370  font.setWeight(QFont::Bold);
1371 
1372  return font;
1373 }
1374 
1376 {
1377  QFont font = QApplication::font();
1378  font.setPointSize(GetMythMainWindow()->NormalizeFontSize(12));
1379  font.setWeight(QFont::Bold);
1380 
1381  return font;
1382 }
1383 
1385 {
1386  if (qobject_cast<QApplication*>(qApp))
1387  {
1388  QCoreApplication::postEvent(
1391  }
1392 }
1393 
1395 {
1396  if (qobject_cast<QApplication*>(qApp))
1397  {
1398  QCoreApplication::postEvent(
1401  }
1402 }
1403 
1405 {
1406  if (qobject_cast<QApplication*>(qApp))
1407  {
1408  QCoreApplication::postEvent(
1411  }
1412 }
1413 
1415 {
1416  if (d->m_screensaver)
1417  {
1418  d->m_screensaver->Disable();
1419  d->m_screensaverEnabled = false;
1420  }
1421 }
1422 
1424 {
1425  if (d->m_screensaver)
1426  {
1427  d->m_screensaver->Restore();
1428  d->m_screensaverEnabled = true;
1429  }
1430 }
1431 
1433 {
1434  if (d->m_screensaver)
1435  {
1436  d->m_screensaver->Reset();
1437  d->m_screensaverEnabled = false;
1438  }
1439 }
1440 
1442 {
1443  return d->m_screensaverEnabled;
1444 }
1445 
1447 {
1448  if (!d->m_screensaver)
1449  return false;
1450 
1451  return d->m_screensaver->Asleep();
1452 }
1453 
1456 void MythUIHelper::SetX11Display(const QString &display)
1457 {
1458  x11_display = display;
1459 }
1460 
1462 {
1463  return x11_display;
1464 }
1465 
1466 void MythUIHelper::AddCurrentLocation(const QString& location)
1467 {
1468  QMutexLocker locker(&m_locationLock);
1469 
1470  if (m_currentLocation.isEmpty() || m_currentLocation.last() != location)
1471  m_currentLocation.push_back(location);
1472 }
1473 
1475 {
1476  QMutexLocker locker(&m_locationLock);
1477 
1478  if (m_currentLocation.isEmpty())
1479  return QString("UNKNOWN");
1480 
1481  return m_currentLocation.takeLast();
1482 }
1483 
1484 QString MythUIHelper::GetCurrentLocation(bool fullPath, bool mainStackOnly)
1485 {
1486  QString result;
1487  QMutexLocker locker(&m_locationLock);
1488 
1489  if (fullPath)
1490  {
1491  // get main stack top screen
1493  result = stack->GetLocation(true);
1494 
1495  if (!mainStackOnly)
1496  {
1497  // get popup stack main screen
1498  stack = GetMythMainWindow()->GetStack("popup stack");
1499 
1500  if (!stack->GetLocation(true).isEmpty())
1501  result += '/' + stack->GetLocation(false);
1502  }
1503 
1504  // if there's a location in the stringlist add that (non mythui screen or external app running)
1505  if (!m_currentLocation.isEmpty())
1506  {
1507  for (int x = 0; x < m_currentLocation.count(); x++)
1508  result += '/' + m_currentLocation[x];
1509  }
1510  }
1511  else
1512  {
1513  // get main stack top screen
1515  result = stack->GetLocation(false);
1516 
1517  if (!mainStackOnly)
1518  {
1519  // get popup stack top screen
1520  stack = GetMythMainWindow()->GetStack("popup stack");
1521 
1522  if (!stack->GetLocation(false).isEmpty())
1523  result = stack->GetLocation(false);
1524  }
1525 
1526  // if there's a location in the stringlist use that (non mythui screen or external app running)
1527  if (!m_currentLocation.isEmpty())
1528  result = m_currentLocation.last();
1529  }
1530 
1531  if (result.isEmpty())
1532  result = "UNKNOWN";
1533 
1534  return result;
1535 }
1536 
1538 {
1539  return d->m_imageThreadPool;
1540 }
1541 
1542 QSize MythUIHelper::GetBaseSize(void) const
1543 {
1544  return d->m_baseSize;
1545 }
1546 
1548 {
1549  d->m_fontStretch = stretch;
1550 }
1551 
1553 {
1554  return d->m_fontStretch;
1555 }
QRect GetScreenBounds(void)
MythImage * CacheImage(const QString &url, MythImage *im, bool nodisk=false)
QString FindThemeDir(const QString &themename, bool doFallback=true)
Returns the full path to the theme denoted by themename.
Controls all instances of the screensaver.
Definition: screensaver.h:43
double GetPixelAspectRatio(void)
QMutex m_locationLock
Definition: mythuihelper.h:147
void SetFontStretch(int stretch)
void Disable(void)
Definition: screensaver.cpp:56
static QString themedir
Definition: mythdirs.cpp:21
MythDisplay * m_display
void LoadQtConfig(void)
void UpdateScreenSettings(void)
QPalette m_palette
Colour scheme.
static QString GetX11Display(void)
bool Load(MythImageReader *reader)
Definition: mythimage.cpp:278
ImageCacheMode
Definition: mythuihelper.h:24
static QFont GetMediumFont(void)
static void DisableScreensaver(void)
bool IsImageInCache(const QString &url)
ScreenSaverControl * m_screensaver
QRect GetScreenSettings(void)
int DecrRef(void) override
Decrements reference count and deletes on 0.
Definition: mythimage.cpp:55
#define LOC
QString GetThumbnailDir(void)
Returns the directory where all non-theme thumbnail files should be cached.
Definition: mythdirs.cpp:249
void RemoveCacheDir(const QString &dirname)
QSize GetBaseSize(void) const
void ClearOldImageCache(void)
QString GetLocation(bool fullPath) const
MythScreenStack * GetStack(const QString &stackname)
bool IsScreenSetup(void)
#define DEFAULT_UI_THEME
Definition: mythuihelper.h:12
void AddCurrentLocation(const QString &location)
void Init(void)
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString GetCurrentLocation(bool fullPath=false, bool mainStackOnly=true)
MythScreenStack * GetMainStack()
void DoResetScreensaver(void)
static QFont GetSmallFont(void)
static QRect GetGeometryOverride(void)
Return the raw geometry override rectangle.
QString GetThemeDir(void)
void Restore(void)
Definition: screensaver.cpp:63
void DestroyMythUI()
bool IsInitialized(void) const
Has Init() been called on this screen?
void SetIsInCache(bool bCached)
Definition: mythimage.cpp:73
bool FindThemeFile(QString &path)
MythUIHelperPrivate(MythUIHelper *p)
MThreadPool * m_imageThreadPool
QString GetCacheDirByUrl(const QString &url)
Look at the url being read and decide whether the cached version should go into the theme cache or th...
static void SetX11Display(const QString &display)
This needs to be set before MythUIHelper is initialized so that the MythUIHelper::Init() can detect X...
QString GetThemeCacheDir(void)
QString FindMenuThemeDir(const QString &menuname)
Returns the full path to the menu theme denoted by menuname.
static MythDisplay * AcquireRelease(bool Acquire=true)
Definition: mythdisplay.cpp:69
virtual bool UsingVideoModes(void)
Definition: mythdisplay.h:29
QStringList GetThemeSearchPath(void)
MythUIHelperPrivate * d
Definition: mythuihelper.h:145
virtual MythScreenType * GetTopScreen(void) const
QStringList m_currentLocation
Definition: mythuihelper.h:148
void DoDisableScreensaver(void)
bool SwitchToGUI(bool Wait=false)
Switches to the GUI resolution.
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QList< ThemeInfo > GetThemes(ThemeType type)
int IncrRef(void) override
Increments reference count.
Definition: mythimage.cpp:47
QString GetShareDir(void)
Definition: mythdirs.cpp:222
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
static void ParseGeometryOverride(const QString &geometry)
Parse an X11 style command line geometry string.
QString GetMenuThemeDir(void)
void ExcludeFromCacheSize(MythImage *im)
void DoRestoreScreensaver(void)
void StoreGUIsettings(void)
Apply any user overrides to the screen geometry.
QDateTime GetLastModified(const QString &url)
Gets the Last Modified timestamp for a URI.
int GetFontStretch(void) const
void UpdateImageCache(void)
unsigned int uint
Definition: compat.h:140
QDateTime LastModified(void) const
QStringList m_searchPaths
static void destroyMythUI(void)
static QFont GetBigFont(void)
QString GetThemeBaseCacheDir(void)
Returns the base directory where all theme related files should be cached.
Definition: mythdirs.cpp:257
MythImage * GetImageFromCache(const QString &url)
Returns a reference counted image base on the URL.
MythUIHelper * GetMythUI()
void SwitchToDesktop(void)
Return the screen to the original desktop video mode.
void RemoveFromCacheByURL(const QString &url)
MythMainWindow * GetMythMainWindow(void)
MythUIHelper * m_parent
MythImage * LoadCacheImage(QString srcfile, const QString &label, MythPainter *painter, ImageCacheMode cacheMode=kCacheNormal)
Returns a reference counted image from the cache.
bool m_themeloaded
Do we have a palette and pixmap to use?
static void RestoreScreensaver(void)
QString GetThemeName(void)
#define FALLBACK_UI_THEME
Definition: mythuihelper.h:13
MythUIMenuCallbacks m_callbacks
ThemeType
Definition: themeinfo.h:14
static bool IsTopScreenInitialized(void)
QMap< QString, qint64 > m_cacheTrack
static void PruneCacheDir(const QString &dirname)
Remove all files in the cache that haven't been accessed in a user configurable number of days.
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static QMutex uiLock
QString RemoveCurrentLocation(void)
QAtomicInteger< qint64 > m_maxCacheSize
void IncludeInCacheSize(MythImage *im)
static QString x11_display
Definition: mythuihelper.h:119
bool GetScreenIsAsleep(void)
static MythUIHelper * getMythUI(void)
string themeName
Definition: mythburn.py:189
QString GetThemesParentDir(void)
Definition: mythdirs.cpp:225
static void ResetScreensaver(void)
Default UTC.
Definition: mythdate.h:14
MythDB * GetMythDB(void)
Definition: mythdb.cpp:46
static MythUIHelper * mythui
static bool IsGeometryOverridden(void)
MThreadPool * GetImageThreadPool(void)
MythImage * GetFormatImage()
Returns a blank reference counted image in the format required for the Draw functions for this painte...
QString GetHostName(void)
QString GetRemoteCacheDir(void)
Returns the directory for all files cached from the backend.
Definition: mythdirs.cpp:241
QMap< QString, MythImage * > m_imageCache
MythUIMenuCallbacks * GetMenuCBs(void)
bool GetScreensaverEnabled(void)
QAtomicInteger< qint64 > m_cacheSize
void RemoveFromCacheByFile(const QString &fname)
void ResetLanguage(void)