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