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 GetScreenBounds(void);
102  void StoreGUIsettings(void);
103  double GetPixelAspectRatio(void);
104 
105  bool m_themeloaded {false};
108  QString m_themename;
109  QPalette m_palette;
110 
111  float m_wmult {1.0F};
112  float m_hmult {1.0F};
113  float m_pixelAspectRatio {-1.0F};
114 
115  // Drawable area of the full screen. May cover several screens,
116  // or exclude windowing system fixtures (like Mac menu bar)
117  int m_xbase {0};
118  int m_ybase {0};
119  int m_height {0};
120  int m_width {0};
121 
122  // Dimensions of the theme
123  int m_baseWidth {800};
124  int m_baseHeight {600};
125  bool m_isWide {false};
126 
127  QMap<QString, MythImage *> m_imageCache;
128 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
129  QMap<QString, uint> m_cacheTrack;
130 #else
131  QMap<QString, qint64> m_cacheTrack;
132 #endif
133  QMutex *m_cacheLock {nullptr};
134 
135 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
136  QAtomicInt m_cacheSize {0};
137  QAtomicInt m_maxCacheSize {30 * 1024 * 1024};
138 #else
139  // This change is because of the QImage change from byteCount() to
140  // sizeInBytes(), the latter returning a 64bit value.
141  QAtomicInteger<qint64> m_cacheSize {0};
142  QAtomicInteger<qint64> m_maxCacheSize {30 * 1024 * 1024};
143 #endif
144 
145  // The part of the screen(s) allocated for the GUI. Unless
146  // overridden by the user, defaults to drawable area above.
147  int m_screenxbase {0};
148  int m_screenybase {0};
149 
150  // The part of the screen(s) allocated for the GUI. Unless
151  // overridden by the user, defaults to drawable area above.
152  int m_screenwidth {0};
153  int m_screenheight {0};
154 
155  // Command-line GUI size, which overrides both the above sets of sizes
156  static int x_override;
157  static int y_override;
158  static int w_override;
159  static int h_override;
160 
162  QString m_userThemeDir;
163 
165  bool m_screensaverEnabled {false};
166 
167  MythDisplay *m_display {nullptr};
168  bool m_screenSetup {false};
169 
171 
172  MythUIMenuCallbacks m_callbacks {nullptr,nullptr,nullptr,nullptr,nullptr};
173 
174  MythUIHelper *m_parent {nullptr};
175 
176  int m_fontStretch {100};
177 
178  QStringList m_searchPaths;
179 };
180 
185 
187 {
188  QMutableMapIterator<QString, MythImage *> i(m_imageCache);
189 
190  while (i.hasNext())
191  {
192  i.next();
193  i.value()->SetIsInCache(false);
194  i.value()->DecrRef();
195  i.remove();
196  }
197 
198  m_cacheTrack.clear();
199 
200  delete m_cacheLock;
201  delete m_imageThreadPool;
202  delete m_screensaver;
203 
204  if (m_display)
205  {
206  if (m_display->UsingVideoModes())
209  }
210 }
211 
213 {
214  if (!m_display)
217  GetScreenBounds();
219  m_screenSetup = true;
220 
221  StorageGroup sgroup("Themes", gCoreContext->GetHostName());
222  m_userThemeDir = sgroup.GetFirstDir(true);
223 }
224 
234 {
235  foreach (QScreen *screen, qGuiApp->screens())
236  {
237  QRect dim = screen->geometry();
238  QString extra = MythDisplay::GetExtraScreenInfo(screen);
239  LOG(VB_GUI, LOG_INFO, LOC + QString("Screen %1 dim: %2x%3 %4")
240  .arg(screen->name())
241  .arg(dim.width()).arg(dim.height())
242  .arg(extra));
243  }
244 
245  QScreen *primary = qGuiApp->primaryScreen();
246  LOG(VB_GUI, LOG_INFO, LOC +
247  QString("Primary screen: %1.").arg(primary->name()));
248 
249  int numScreens = m_display->GetScreenCount();
250  QSize dim = primary->virtualSize();
251  LOG(VB_GUI, LOG_INFO, LOC +
252  QString("Total desktop dim: %1x%2, over %3 screen[s].")
253  .arg(dim.width()).arg(dim.height()).arg(numScreens));
254 
256  {
257  LOG(VB_GUI, LOG_INFO, LOC + QString("Using entire desktop."));
258  m_xbase = 0;
259  m_ybase = 0;
260  m_width = dim.width();
261  m_height = dim.height();
262  return;
263  }
264 
265  QRect bounds;
266  QScreen *screen = m_display->GetCurrentScreen();
267  if (GetMythDB()->GetBoolSetting("RunFrontendInWindow", false))
268  {
269  LOG(VB_GUI, LOG_INFO, LOC + "Running in a window");
270  // This doesn't include the area occupied by the
271  // Windows taskbar, or the Mac OS X menu bar and Dock
272  bounds = screen->availableGeometry();
273  }
274  else
275  {
276  bounds = screen->geometry();
277  }
278  m_xbase = bounds.x();
279  m_ybase = bounds.y();
280  m_width = bounds.width();
281  m_height = bounds.height();
282 
283  LOG(VB_GUI, LOG_INFO, LOC + QString("Using screen %1, %2x%3 at %4,%5")
284  .arg(screen->name()).arg(m_width).arg(m_height)
285  .arg(m_xbase).arg(m_ybase));
286 }
287 
292 {
293  if (x_override >= 0 && y_override >= 0)
294  {
295  GetMythDB()->OverrideSettingForSession("GuiOffsetX", QString::number(x_override));
296  GetMythDB()->OverrideSettingForSession("GuiOffsetY", QString::number(y_override));
297  }
298 
299  if (w_override > 0 && h_override > 0)
300  {
301  GetMythDB()->OverrideSettingForSession("GuiWidth", QString::number(w_override));
302  GetMythDB()->OverrideSettingForSession("GuiHeight", QString::number(h_override));
303  }
304 
305  m_screenxbase = GetMythDB()->GetNumSetting("GuiOffsetX");
306  m_screenybase = GetMythDB()->GetNumSetting("GuiOffsetY");
307 
309  GetMythDB()->GetResolutionSetting("Gui", m_screenwidth, m_screenheight);
310 
311  // If any of these was _not_ set by the user,
312  // (i.e. they are 0) use the whole-screen defaults
313 
314  if (!m_screenxbase)
316 
317  if (!m_screenybase)
319 
320  if (!m_screenwidth)
322 
323  if (!m_screenheight)
325 
326  if (m_screenheight < 160 || m_screenwidth < 160)
327  {
328  LOG(VB_GENERAL, LOG_ERR, LOC +
329  "Somehow, your screen size settings are bad.\n\t\t\t" +
330  QString("GuiResolution: %1\n\t\t\t")
331  .arg(GetMythDB()->GetSetting("GuiResolution")) +
332  QString(" old GuiWidth: %1\n\t\t\t")
333  .arg(GetMythDB()->GetNumSetting("GuiWidth")) +
334  QString(" old GuiHeight: %1\n\t\t\t")
335  .arg(GetMythDB()->GetNumSetting("GuiHeight")) +
336  QString("m_width: %1").arg(m_width) +
337  QString("m_height: %1\n\t\t\t").arg(m_height) +
338  "Falling back to 640x480");
339 
340  m_screenwidth = 640;
341  m_screenheight = 480;
342  }
343 
344  m_wmult = m_screenwidth / (float)m_baseWidth;
346 
347  // Default font, _ALL_ fonts inherit from this!
348  // e.g All fonts will be 19 pixels unless a new size is explicitly defined.
349  QFont font = QFont("Arial");
350 
351  if (!font.exactMatch())
352  font = QFont();
353 
354  font.setStyleHint(QFont::SansSerif, QFont::PreferAntialias);
355  font.setPixelSize(lroundf(19.0F * m_hmult));
356  int stretch = (int)(100 / GetPixelAspectRatio());
357  font.setStretch(stretch); // QT
358  m_fontStretch = stretch; // MythUI
359 
360  QApplication::setFont(font);
361 }
362 
364 {
365  if (m_pixelAspectRatio < 0)
366  {
367  if (!m_display)
369  m_pixelAspectRatio = static_cast<float>(m_display->GetPixelAspectRatio());
370  }
371  return static_cast<double>(m_pixelAspectRatio);
372 }
373 
375 {
376  d = new MythUIHelperPrivate(this);
377 }
378 
380 {
381  delete d;
382 }
383 
385 {
386  d->Init();
387  d->m_callbacks = cbs;
388 
389  d->m_maxCacheSize.fetchAndStoreRelease(
390  GetMythDB()->GetNumSetting("UIImageCacheSize", 30) * 1024 * 1024);
391 
392  LOG(VB_GUI, LOG_INFO, LOC +
393  QString("MythUI Image Cache size set to %1 bytes")
394  .arg(d->m_maxCacheSize.fetchAndAddRelease(0)));
395 }
396 
397 // This init is used for showing the startup UI that is shown
398 // before the database is initialized. The above init is called later,
399 // after the DB is available.
400 // This class does not mind being Initialized twice.
402 {
403  d->Init();
404 }
405 
407 {
408  return &(d->m_callbacks);
409 }
410 
412 {
413  return d->m_screenSetup;
414 }
415 
417 {
419 }
420 
422 {
424  d->m_themecachedir.clear();
425 
426  if (!d->m_display)
428 
429  // Switch to desired GUI resolution
430  if (d->m_display->UsingVideoModes())
432 
433  // Note the possibly changed screen settings
434  d->GetScreenBounds();
435 
436  qApp->setStyle("Windows");
437 
438  QString themename = GetMythDB()->GetSetting("Theme", DEFAULT_UI_THEME);
439  QString themedir = FindThemeDir(themename);
440 
441  auto *themeinfo = new ThemeInfo(themedir);
442  if (themeinfo)
443  {
444  d->m_isWide = themeinfo->IsWide();
445  d->m_baseWidth = themeinfo->GetBaseRes()->width();
446  d->m_baseHeight = themeinfo->GetBaseRes()->height();
447  d->m_themename = themeinfo->GetName();
448  LOG(VB_GUI, LOG_INFO, LOC +
449  QString("Using theme base resolution of %1x%2")
450  .arg(d->m_baseWidth).arg(d->m_baseHeight));
451  delete themeinfo;
452  }
453 
454  // Recalculate GUI dimensions
455  d->StoreGUIsettings();
456 
457  d->m_themepathname = themedir + '/';
458  d->m_searchPaths.clear();
459 
460  d->m_themeloaded = false;
461 
462  themename = GetMythDB()->GetSetting("MenuTheme", "defaultmenu");
463 
464  if (themename == "default")
465  themename = "defaultmenu";
466 
467  d->m_menuthemepathname = FindMenuThemeDir(themename);
468 }
469 
471 {
472  QMutexLocker locker(d->m_cacheLock);
473 
474  QMutableMapIterator<QString, MythImage *> i(d->m_imageCache);
475 
476  while (i.hasNext())
477  {
478  i.next();
479  i.value()->SetIsInCache(false);
480  i.value()->DecrRef();
481  i.remove();
482  }
483 
484  d->m_cacheTrack.clear();
485 
486  d->m_cacheSize.fetchAndStoreOrdered(0);
487 
491 }
492 
494 {
495  QMutexLocker locker(d->m_cacheLock);
496 
497  if (d->m_imageCache.contains(url))
498  {
499 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
500  d->m_cacheTrack[url] = MythDate::current().toTime_t();
501 #else
502  d->m_cacheTrack[url] = MythDate::current().toSecsSinceEpoch();
503 #endif
504  d->m_imageCache[url]->IncrRef();
505  return d->m_imageCache[url];
506  }
507 
508  /*
509  if (QFileInfo(url).exists())
510  {
511  MythImage *im = GetMythPainter()->GetFormatImage();
512  im->Load(url,false);
513  return im;
514  }
515  */
516 
517  return nullptr;
518 }
519 
521 {
522  if (im)
523 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
524  d->m_cacheSize.fetchAndAddOrdered(im->byteCount());
525 #else
526  d->m_cacheSize.fetchAndAddOrdered(im->sizeInBytes());
527 #endif
528 }
529 
531 {
532  if (im)
533 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
534  d->m_cacheSize.fetchAndAddOrdered(-im->byteCount());
535 #else
536  d->m_cacheSize.fetchAndAddOrdered(-im->sizeInBytes());
537 #endif
538 }
539 
541  bool nodisk)
542 {
543  if (!im)
544  return nullptr;
545 
546  if (!nodisk)
547  {
548  QString dstfile = GetCacheDirByUrl(url) + '/' + url;
549 
550  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
551  QString("Saved to Cache (%1)").arg(dstfile));
552 
553  // Save to disk cache
554  im->save(dstfile, "PNG");
555  }
556 
557  // delete the oldest cached images until we fall below threshold.
558  QMutexLocker locker(d->m_cacheLock);
559 
560  while ((d->m_cacheSize.fetchAndAddOrdered(0) +
561 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
562  im->byteCount()
563 #else
564  im->sizeInBytes()
565 #endif
566  ) >=
567  d->m_maxCacheSize.fetchAndAddOrdered(0) &&
568  !d->m_imageCache.empty())
569  {
570  QMap<QString, MythImage *>::iterator it = d->m_imageCache.begin();
571 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
572  uint oldestTime = MythDate::current().toTime_t();
573 #else
574  qint64 oldestTime = MythDate::current().toSecsSinceEpoch();
575 #endif
576  QString oldestKey = it.key();
577 
578  int count = 0;
579 
580  for (; it != d->m_imageCache.end(); ++it)
581  {
582  if (d->m_cacheTrack[it.key()] < oldestTime)
583  {
584  if ((2 == it.value()->IncrRef()) && (it.value() != im))
585  {
586  oldestTime = d->m_cacheTrack[it.key()];
587  oldestKey = it.key();
588  count++;
589  }
590  it.value()->DecrRef();
591  }
592  }
593 
594  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
595  QString("%1 images are eligible for expiry").arg(count));
596 
597  if (count > 0)
598  {
599  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
600  QString("Cache too big (%1), removing :%2:")
601  .arg(d->m_cacheSize.fetchAndAddOrdered(0) +
602 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
603  im->byteCount()
604 #else
605  im->sizeInBytes()
606 #endif
607  )
608  .arg(oldestKey));
609 
610  d->m_imageCache[oldestKey]->SetIsInCache(false);
611  d->m_imageCache[oldestKey]->DecrRef();
612  d->m_imageCache.remove(oldestKey);
613  d->m_cacheTrack.remove(oldestKey);
614  }
615  else
616  {
617  break;
618  }
619  }
620 
621  QMap<QString, MythImage *>::iterator it = d->m_imageCache.find(url);
622 
623  if (it == d->m_imageCache.end())
624  {
625  im->IncrRef();
626  d->m_imageCache[url] = im;
627 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
628  d->m_cacheTrack[url] = MythDate::current().toTime_t();
629 #else
630  d->m_cacheTrack[url] = MythDate::current().toSecsSinceEpoch();
631 #endif
632 
633  im->SetIsInCache(true);
634  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
635  QString("NOT IN RAM CACHE, Adding, and adding to size :%1: :%2:")
636  .arg(url)
637 #if QT_VERSION < QT_VERSION_CHECK(5,10,0)
638  .arg(im->byteCount())
639 #else
640  .arg(im->sizeInBytes())
641 #endif
642  );
643  }
644 
645  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
646  QString("MythUIHelper::CacheImage : Cache Count = :%1: size :%2:")
647  .arg(d->m_imageCache.count())
648  .arg(d->m_cacheSize.fetchAndAddRelaxed(0)));
649 
650  return d->m_imageCache[url];
651 }
652 
653 void MythUIHelper::RemoveFromCacheByURL(const QString &url)
654 {
655  QMutexLocker locker(d->m_cacheLock);
656  QMap<QString, MythImage *>::iterator it = d->m_imageCache.find(url);
657 
658  if (it != d->m_imageCache.end())
659  {
660  d->m_imageCache[url]->SetIsInCache(false);
661  d->m_imageCache[url]->DecrRef();
662  d->m_imageCache.remove(url);
663  d->m_cacheTrack.remove(url);
664  }
665 
666  QString dstfile;
667 
668  dstfile = GetCacheDirByUrl(url) + '/' + url;
669  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
670  QString("RemoveFromCacheByURL removed :%1: from cache").arg(dstfile));
671  QFile::remove(dstfile);
672 }
673 
674 void MythUIHelper::RemoveFromCacheByFile(const QString &fname)
675 {
676  QList<QString>::iterator it;
677 
678  QString partialKey = fname;
679  partialKey.replace('/', '-');
680 
681  d->m_cacheLock->lock();
682  QList<QString> m_imageCacheKeys = d->m_imageCache.keys();
683  d->m_cacheLock->unlock();
684 
685  for (it = m_imageCacheKeys.begin(); it != m_imageCacheKeys.end(); ++it)
686  {
687  if ((*it).contains(partialKey))
689  }
690 
691  // Loop through files to cache any that were not caught by
692  // RemoveFromCacheByURL
693  QDir dir(GetThemeCacheDir());
694  QFileInfoList list = dir.entryInfoList();
695 
696  for (int i = 0; i < list.size(); ++i)
697  {
698  const QFileInfo& fileInfo = list.at(i);
699 
700  if (fileInfo.fileName().contains(partialKey))
701  {
702  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
703  QString("RemoveFromCacheByFile removed: %1: from cache")
704  .arg(fileInfo.fileName()));
705 
706  if (!dir.remove(fileInfo.fileName()))
707  LOG(VB_GENERAL, LOG_ERR, LOC +
708  QString("Failed to delete %1 from the theme cache")
709  .arg(fileInfo.fileName()));
710  }
711  }
712 }
713 
714 bool MythUIHelper::IsImageInCache(const QString &url)
715 {
716  QMutexLocker locker(d->m_cacheLock);
717 
718  if (d->m_imageCache.contains(url))
719  return true;
720 
721  if (QFileInfo(url).exists())
722  return true;
723 
724  return false;
725 }
726 
728 {
729  static QString s_oldcachedir;
730  QString tmpcachedir = GetThemeBaseCacheDir() + "/" +
731  GetMythDB()->GetSetting("Theme", DEFAULT_UI_THEME) +
732  "." + QString::number(d->m_screenwidth) +
733  "." + QString::number(d->m_screenheight);
734 
735  if (tmpcachedir != s_oldcachedir)
736  {
737  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
738  QString("Creating cache dir: %1").arg(tmpcachedir));
739  QDir dir;
740  dir.mkdir(tmpcachedir);
741  s_oldcachedir = tmpcachedir;
742  }
743  return tmpcachedir;
744 }
745 
753 QString MythUIHelper::GetCacheDirByUrl(const QString& url)
754 {
755  if (url.startsWith("myth:") || url.startsWith("-"))
756  return GetThumbnailDir();
757  return GetThemeCacheDir();
758 }
759 
761 {
763 
764  QString themecachedir = d->m_themecachedir;
765 
766  d->m_themecachedir += '/';
767 
768  QDir dir(GetThemeBaseCacheDir());
769  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
770  QFileInfoList list = dir.entryInfoList();
771 
772  QFileInfoList::const_iterator it = list.begin();
773  QMap<QDateTime, QString> dirtimes;
774 
775  while (it != list.end())
776  {
777  const QFileInfo *fi = &(*it++);
778 
779  if (fi->isDir() && !fi->isSymLink())
780  {
781  if (fi->absoluteFilePath() == themecachedir)
782  continue;
783 
784  dirtimes[fi->lastModified()] = fi->absoluteFilePath();
785  }
786  }
787 
788  // Cache two themes/resolutions to allow sampling other themes without
789  // incurring a penalty. Especially for those writing new themes or testing
790  // changes of an existing theme. The space used is neglible when compared
791  // against the average video
792  while ((size_t)dirtimes.size() >= 2)
793  {
794  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC + QString("Removing cache dir: %1")
795  .arg(dirtimes.begin().value()));
796 
797  RemoveCacheDir(dirtimes.begin().value());
798  dirtimes.erase(dirtimes.begin());
799  }
800 
801  QMap<QDateTime, QString>::const_iterator dit = dirtimes.begin();
802 
803  for (; dit != dirtimes.end(); ++dit)
804  {
805  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
806  QString("Keeping cache dir: %1").arg(*dit));
807  }
808 }
809 
810 void MythUIHelper::RemoveCacheDir(const QString &dirname)
811 {
812  QString cachedirname = GetThemeBaseCacheDir();
813 
814  if (!dirname.startsWith(cachedirname))
815  return;
816 
817  LOG(VB_GENERAL, LOG_ERR, LOC +
818  QString("Removing stale cache dir: %1").arg(dirname));
819 
820  QDir dir(dirname);
821 
822  if (!dir.exists())
823  return;
824 
825  dir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
826  QFileInfoList list = dir.entryInfoList();
827  QFileInfoList::const_iterator it = list.begin();
828 
829  while (it != list.end())
830  {
831  const QFileInfo *fi = &(*it++);
832 
833  if (fi->isFile() && !fi->isSymLink())
834  {
835  QFile file(fi->absoluteFilePath());
836  file.remove();
837  }
838  else if (fi->isDir() && !fi->isSymLink())
839  {
840  RemoveCacheDir(fi->absoluteFilePath());
841  }
842  }
843 
844  dir.rmdir(dirname);
845 }
846 
853 void MythUIHelper::PruneCacheDir(const QString& dirname)
854 {
855  int days = GetMythDB()->GetNumSetting("UIDiskCacheDays", 7);
856  if (days == -1) {
857  LOG(VB_GENERAL, LOG_INFO, LOC +
858  QString("Pruning cache directory: %1 is disabled").arg(dirname));
859  return;
860  }
861 
862  LOG(VB_GENERAL, LOG_INFO, LOC +
863  QString("Pruning cache directory: %1").arg(dirname));
864  QDateTime cutoff = MythDate::current().addDays(-days);
865 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
866  qint64 cutoffsecs = cutoff.toMSecsSinceEpoch()/1000;
867 #else
868  qint64 cutoffsecs = cutoff.toSecsSinceEpoch();
869 #endif
870 
871  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
872  QString("Removing files not accessed since %1")
873  .arg(cutoff.toLocalTime().toString(Qt::ISODate)));
874 
875  int kept = 0, deleted = 0, errcnt = 0;
876  QDir dir(dirname);
877  dir.setFilter(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
878  dir.setSorting(QDir::NoSort);
879 
880  // Trying to save every cycle possible within this loop. The
881  // stat() call seems significantly faster than the fi.fileRead()
882  // method. The documentation for QFileInfo says that the
883  // fi.absoluteFilePath() method has to query the file system, so
884  // use fi.filePath() method here and then add the directory if
885  // needed. Using dir.entryList() and adding the dirname each time
886  // is also slower just using dir.entryInfoList().
887  foreach (const QFileInfo &fi, dir.entryInfoList())
888  {
889  struct stat buf {};
890  QString fullname = fi.filePath();
891  if (not fullname.startsWith('/'))
892  fullname = dirname + "/" + fullname;
893  QByteArray fullname8 = fullname.toLocal8Bit();
894  int rc = stat(fullname8, &buf);
895  if (rc == -1)
896  {
897  errcnt += 1;
898  continue;
899  }
900  if (buf.st_atime >= cutoffsecs)
901  {
902  kept += 1;
903  LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
904  QString("%1 Keep %2")
905  .arg(fi.lastRead().toLocalTime().toString(Qt::ISODate))
906  .arg(fi.fileName()));
907  continue;
908  }
909  deleted += 1;
910  LOG(VB_GUI | VB_FILE, LOG_DEBUG, LOC +
911  QString("%1 Delete %2")
912  .arg(fi.lastRead().toLocalTime().toString(Qt::ISODate))
913  .arg(fi.fileName()));
914  unlink(fullname8);
915  }
916 
917  LOG(VB_GENERAL, LOG_INFO, LOC +
918  QString("Kept %1 files, deleted %2 files, stat error on %3 files")
919  .arg(kept).arg(deleted).arg(errcnt));
920 }
921 
922 void MythUIHelper::GetScreenBounds(int &xbase, int &ybase,
923  int &width, int &height)
924 {
925  xbase = d->m_xbase;
926  ybase = d->m_ybase;
927 
928  width = d->m_width;
929  height = d->m_height;
930 }
931 
932 void MythUIHelper::GetScreenSettings(float &wmult, float &hmult)
933 {
934  wmult = d->m_wmult;
935  hmult = d->m_hmult;
936 }
937 
938 void MythUIHelper::GetScreenSettings(int &width, float &wmult,
939  int &height, float &hmult)
940 {
941  height = d->m_screenheight;
942  width = d->m_screenwidth;
943 
944  wmult = d->m_wmult;
945  hmult = d->m_hmult;
946 }
947 
948 void MythUIHelper::GetScreenSettings(int &xbase, int &width, float &wmult,
949  int &ybase, int &height, float &hmult)
950 {
951  xbase = d->m_screenxbase;
952  ybase = d->m_screenybase;
953 
954  height = d->m_screenheight;
955  width = d->m_screenwidth;
956 
957  wmult = d->m_wmult;
958  hmult = d->m_hmult;
959 }
960 
970 void MythUIHelper::ParseGeometryOverride(const QString &geometry)
971 {
972  QRegExp sre("^(\\d+)x(\\d+)$");
973  QRegExp lre("^(\\d+)x(\\d+)([+-]\\d+)([+-]\\d+)$");
974  QStringList geo;
975  bool longForm = false;
976 
977  if (sre.exactMatch(geometry))
978  {
979  geo = sre.capturedTexts();
980  }
981  else if (lre.exactMatch(geometry))
982  {
983  geo = lre.capturedTexts();
984  longForm = true;
985  }
986  else
987  {
988  LOG(VB_GENERAL, LOG_ERR, LOC +
989  "Geometry does not match either form -\n\t\t\t"
990  "WIDTHxHEIGHT or WIDTHxHEIGHT+XOFF+YOFF");
991  return;
992  }
993 
994  bool parsed = false;
995  int tmp_w = 0, tmp_h = 0;
996 
997  tmp_w = geo[1].toInt(&parsed);
998 
999  if (!parsed)
1000  {
1001  LOG(VB_GENERAL, LOG_ERR, LOC +
1002  "Could not parse width of geometry override");
1003  }
1004 
1005  if (parsed)
1006  {
1007  tmp_h = geo[2].toInt(&parsed);
1008 
1009  if (!parsed)
1010  {
1011  LOG(VB_GENERAL, LOG_ERR, LOC +
1012  "Could not parse height of geometry override");
1013  }
1014  }
1015 
1016  if (parsed)
1017  {
1020  LOG(VB_GENERAL, LOG_INFO, LOC +
1021  QString("Overriding GUI size: width=%1 height=%2")
1022  .arg(tmp_w).arg(tmp_h));
1023  }
1024  else
1025  {
1026  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to override GUI size.");
1027  }
1028 
1029  if (longForm)
1030  {
1031  int tmp_x = geo[3].toInt(&parsed);
1032  if (!parsed)
1033  {
1034  LOG(VB_GENERAL, LOG_ERR, LOC +
1035  "Could not parse horizontal offset of geometry override");
1036  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to override GUI offset.");
1037  return;
1038  }
1039 
1040  int tmp_y = geo[4].toInt(&parsed);
1041  if (!parsed)
1042  {
1043  LOG(VB_GENERAL, LOG_ERR, LOC +
1044  "Could not parse vertical offset of geometry override");
1045  LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to override GUI offset.");
1046  return;
1047  }
1048 
1051  LOG(VB_GENERAL, LOG_INFO, LOC +
1052  QString("Overriding GUI offset: x=%1 y=%2")
1053  .arg(tmp_x).arg(tmp_y));
1054  }
1055 }
1056 
1058 {
1059  return (MythUIHelperPrivate::x_override >= 0 ||
1063 }
1064 
1076 QString MythUIHelper::FindThemeDir(const QString &themename, bool doFallback)
1077 {
1078  QString testdir;
1079  QDir dir;
1080 
1081  if (!themename.isEmpty())
1082  {
1083  testdir = d->m_userThemeDir + themename;
1084 
1085  dir.setPath(testdir);
1086 
1087  if (dir.exists())
1088  return testdir;
1089 
1090  testdir = GetThemesParentDir() + themename;
1091  dir.setPath(testdir);
1092 
1093  if (dir.exists())
1094  return testdir;
1095 
1096  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No theme dir: '%1'")
1097  .arg(dir.absolutePath()));
1098  }
1099 
1100  if (!doFallback)
1101  return QString();
1102 
1103  testdir = GetThemesParentDir() + DEFAULT_UI_THEME;
1104  dir.setPath(testdir);
1105 
1106  if (dir.exists())
1107  {
1108  LOG(VB_GENERAL, LOG_ERR, LOC +
1109  QString("Could not find theme: %1 - Switching to %2")
1110  .arg(themename).arg(DEFAULT_UI_THEME));
1111  GetMythDB()->OverrideSettingForSession("Theme", DEFAULT_UI_THEME);
1112  return testdir;
1113  }
1114 
1115  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("No default theme dir: '%1'")
1116  .arg(dir.absolutePath()));
1117 
1118  testdir = GetThemesParentDir() + FALLBACK_UI_THEME;
1119  dir.setPath(testdir);
1120 
1121  if (dir.exists())
1122  {
1123  LOG(VB_GENERAL, LOG_ERR, LOC +
1124  QString("Could not find theme: %1 - Switching to %2")
1125  .arg(themename).arg(FALLBACK_UI_THEME));
1126  GetMythDB()->OverrideSettingForSession("Theme", FALLBACK_UI_THEME);
1127  return testdir;
1128  }
1129 
1130  LOG(VB_GENERAL, LOG_ERR, LOC + QString("No fallback GUI theme dir: '%1'")
1131  .arg(dir.absolutePath()));
1132 
1133  return QString();
1134 }
1135 
1144 QString MythUIHelper::FindMenuThemeDir(const QString &menuname)
1145 {
1146  QString testdir;
1147  QDir dir;
1148 
1149  testdir = d->m_userThemeDir + menuname;
1150 
1151  dir.setPath(testdir);
1152 
1153  if (dir.exists())
1154  return testdir;
1155 
1156  testdir = GetThemesParentDir() + menuname;
1157  dir.setPath(testdir);
1158 
1159  if (dir.exists())
1160  return testdir;
1161 
1162  testdir = GetShareDir();
1163  dir.setPath(testdir);
1164 
1165  if (dir.exists())
1166  {
1167  LOG(VB_GENERAL, LOG_ERR, LOC +
1168  QString("Could not find menu theme: %1 - Switching to default")
1169  .arg(menuname));
1170 
1171  GetMythDB()->SaveSetting("MenuTheme", "default");
1172  return testdir;
1173  }
1174 
1175  LOG(VB_GENERAL, LOG_ERR, LOC +
1176  QString("Could not find menu theme: %1 - Fallback to default failed.")
1177  .arg(menuname));
1178 
1179  return QString();
1180 }
1181 
1183 {
1184  return d->m_menuthemepathname;
1185 }
1186 
1188 {
1189  return d->m_themepathname;
1190 }
1191 
1193 {
1194  return d->m_themename;
1195 }
1196 
1198 {
1199  if (!d->m_searchPaths.isEmpty())
1200  return d->m_searchPaths;
1201 
1202  // traverse up the theme inheritance list adding their location to the search path
1203  QList<ThemeInfo> themeList = GetThemes(THEME_UI);
1204  bool found = true;
1205  QString themeName = d->m_themename;
1206  QString baseName;
1207  QString dirName;
1208 
1209  while (found && !themeName.isEmpty())
1210  {
1211  // find the ThemeInfo for this theme
1212  found = false;
1213  baseName = "";
1214  dirName = "";
1215 
1216  for (int x = 0; x < themeList.count(); x++)
1217  {
1218  if (themeList.at(x).GetName() == themeName)
1219  {
1220  found = true;
1221  baseName = themeList.at(x).GetBaseTheme();
1222  dirName = themeList.at(x).GetDirectoryName();
1223  break;
1224  }
1225  }
1226 
1227  // try to find where the theme is installed
1228  if (found)
1229  {
1230  QString themedir = FindThemeDir(dirName, false);
1231  if (!themedir.isEmpty())
1232  {
1233  LOG(VB_GUI, LOG_INFO, LOC + QString("Adding path '%1' to theme search paths").arg(themedir));
1234  d->m_searchPaths.append(themedir + '/');
1235  }
1236  else
1237  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Could not find ui theme location: %1").arg(themedir));
1238  }
1239  else
1240  {
1241  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Could not find inherited theme: %1").arg(themeName));
1242  }
1243 
1244  themeName = baseName;
1245  }
1246 
1247  if (d->m_isWide)
1248  d->m_searchPaths.append(GetThemesParentDir() + "default-wide/");
1249 
1250  d->m_searchPaths.append(GetThemesParentDir() + "default/");
1251  d->m_searchPaths.append("/tmp/");
1252  return d->m_searchPaths;
1253 }
1254 
1256 {
1257  QFileInfoList fileList;
1258  QList<ThemeInfo> themeList;
1259  QDir themeDirs(GetThemesParentDir());
1260  themeDirs.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
1261  themeDirs.setSorting(QDir::Name | QDir::IgnoreCase);
1262 
1263  fileList.append(themeDirs.entryInfoList());
1264 
1265  themeDirs.setPath(d->m_userThemeDir);
1266 
1267  fileList.append(themeDirs.entryInfoList());
1268 
1269  for (QFileInfoList::iterator it = fileList.begin();
1270  it != fileList.end(); ++it)
1271  {
1272  QFileInfo &theme = *it;
1273 
1274  if (theme.baseName() == "default" ||
1275  theme.baseName() == "default-wide" ||
1276  theme.baseName() == "Slave")
1277  continue;
1278 
1279  ThemeInfo themeInfo(theme.absoluteFilePath());
1280 
1281  if (themeInfo.GetType() & type)
1282  themeList.append(themeInfo);
1283  }
1284 
1285  return themeList;
1286 }
1287 
1288 bool MythUIHelper::FindThemeFile(QString &path)
1289 {
1290  QFileInfo fi(path);
1291 
1292  if (fi.isAbsolute() && fi.exists())
1293  return true;
1294 #ifdef Q_OS_ANDROID
1295  if (path.startsWith("assets:/") && fi.exists())
1296  return true;
1297 #endif
1298 
1299  QString file;
1300  bool foundit = false;
1301  const QStringList searchpath = GetThemeSearchPath();
1302 
1303  for (QStringList::const_iterator ii = searchpath.begin();
1304  ii != searchpath.end(); ++ii)
1305  {
1306  if (fi.isRelative())
1307  {
1308  file = *ii + fi.filePath();
1309  }
1310  else if (fi.isAbsolute() && !fi.isRoot())
1311  {
1312  file = *ii + fi.fileName();
1313  }
1314 
1315  if (QFile::exists(file))
1316  {
1317  path = file;
1318  foundit = true;
1319  break;
1320  }
1321  }
1322 
1323  return foundit;
1324 }
1325 
1326 MythImage *MythUIHelper::LoadCacheImage(QString srcfile, const QString& label,
1327  MythPainter *painter,
1328  ImageCacheMode cacheMode)
1329 {
1330  LOG(VB_GUI | VB_FILE, LOG_INFO, LOC +
1331  QString("LoadCacheImage(%1,%2)").arg(srcfile).arg(label));
1332 
1333  if (srcfile.isEmpty() || label.isEmpty())
1334  return nullptr;
1335 
1336  if (!(kCacheForceStat & cacheMode))
1337  {
1338  // Some screens include certain images dozens or even hundreds of
1339  // times. Even if the image is in the cache, there is still a
1340  // stat system call on the original file to see if it has changed.
1341  // This code relaxes the original-file check so that the check
1342  // isn't repeated if it was already done within kImageCacheTimeout
1343  // seconds.
1344 
1345  // This only applies to the MEMORY cache
1346  const uint kImageCacheTimeout = 60;
1347 #if QT_VERSION < QT_VERSION_CHECK(5,8,0)
1348  uint now = MythDate::current().toTime_t();
1349 #else
1350  qint64 now = MythDate::current().toSecsSinceEpoch();
1351 #endif
1352 
1353  QMutexLocker locker(d->m_cacheLock);
1354 
1355  if (d->m_imageCache.contains(label) &&
1356  d->m_cacheTrack[label] + kImageCacheTimeout > now)
1357  {
1358  d->m_imageCache[label]->IncrRef();
1359  return d->m_imageCache[label];
1360  }
1361  }
1362 
1363  MythImage *ret = nullptr;
1364 
1365  // Check Memory Cache
1366  ret = GetImageFromCache(label);
1367 
1368  // If the image is in the memory or we are not ignoring the disk cache
1369  // then proceed to check whether the source file is newer than our cached
1370  // copy
1371  if (ret || !(cacheMode & kCacheIgnoreDisk))
1372  {
1373  // Create url to image in disk cache
1374  QString cachefilepath;
1375  cachefilepath = GetCacheDirByUrl(label) + '/' + label;
1376  QFileInfo cacheFileInfo(cachefilepath);
1377 
1378  // If the file isn't in the disk cache, then we don't want to bother
1379  // checking the last modified times of the original
1380  if (!cacheFileInfo.exists())
1381  return nullptr;
1382 
1383  // Now compare the time on the source versus our cached copy
1384  QDateTime srcLastModified;
1385 
1386  // For internet images this involves querying the headers of the remote
1387  // image. This is slow even without redownloading the whole image
1388  if ((srcfile.startsWith("http://")) ||
1389  (srcfile.startsWith("https://")) ||
1390  (srcfile.startsWith("ftp://")))
1391  {
1392  // If the image is in the memory cache then skip the last modified
1393  // check, since memory cached images are loaded in the foreground
1394  // this can cause an intolerable delay. The images won't stay in
1395  // the cache forever and so eventually they will be checked.
1396  if (ret)
1397  srcLastModified = cacheFileInfo.lastModified();
1398  else
1399  {
1400  srcLastModified =
1402  }
1403  }
1404  else if (srcfile.startsWith("myth://"))
1405  srcLastModified = RemoteFile::LastModified(srcfile);
1406  else
1407  {
1408  if (!FindThemeFile(srcfile))
1409  return nullptr;
1410 
1411  QFileInfo original(srcfile);
1412 
1413  if (original.exists())
1414  srcLastModified = original.lastModified();
1415  }
1416 
1417  // Now compare the timestamps, if the cached image is newer than the
1418  // source image we can use it, otherwise we want to remove it from the
1419  // cache
1420  if (cacheFileInfo.lastModified() >= srcLastModified)
1421  {
1422  // If we haven't already loaded the image from the memory cache
1423  // and we're not ignoring the disk cache, then it's time to load
1424  // it from there instead
1425  if (!ret && (cacheMode == kCacheNormal))
1426  {
1427 
1428  if (painter)
1429  {
1430  ret = painter->GetFormatImage();
1431 
1432  // Load file from disk cache to memory cache
1433  if (ret->Load(cachefilepath))
1434  {
1435  // Add to ram cache, and skip saving to disk since that is
1436  // where we found this in the first place.
1437  CacheImage(label, ret, true);
1438  }
1439  else
1440  {
1441  LOG(VB_GUI | VB_FILE, LOG_WARNING, LOC +
1442  QString("LoadCacheImage: Could not load :%1")
1443  .arg(cachefilepath));
1444 
1445  ret->SetIsInCache(false);
1446  ret->DecrRef();
1447  ret = nullptr;
1448  }
1449  }
1450  }
1451  }
1452  else
1453  {
1454  ret = nullptr;
1455  // If file has changed on disk, then remove it from the memory
1456  // and disk cache
1457  RemoveFromCacheByURL(label);
1458  }
1459  }
1460 
1461  return ret;
1462 }
1463 
1465 {
1466  QFont font = QApplication::font();
1467  font.setPointSize(GetMythMainWindow()->NormalizeFontSize(25));
1468  font.setWeight(QFont::Bold);
1469 
1470  return font;
1471 }
1472 
1474 {
1475  QFont font = QApplication::font();
1476  font.setPointSize(GetMythMainWindow()->NormalizeFontSize(16));
1477  font.setWeight(QFont::Bold);
1478 
1479  return font;
1480 }
1481 
1483 {
1484  QFont font = QApplication::font();
1485  font.setPointSize(GetMythMainWindow()->NormalizeFontSize(12));
1486  font.setWeight(QFont::Bold);
1487 
1488  return font;
1489 }
1490 
1492 {
1493  if (qobject_cast<QApplication*>(qApp))
1494  {
1495  QCoreApplication::postEvent(
1498  }
1499 }
1500 
1502 {
1503  if (qobject_cast<QApplication*>(qApp))
1504  {
1505  QCoreApplication::postEvent(
1508  }
1509 }
1510 
1512 {
1513  if (qobject_cast<QApplication*>(qApp))
1514  {
1515  QCoreApplication::postEvent(
1518  }
1519 }
1520 
1522 {
1523  if (d->m_screensaver)
1524  {
1525  d->m_screensaver->Disable();
1526  d->m_screensaverEnabled = false;
1527  }
1528 }
1529 
1531 {
1532  if (d->m_screensaver)
1533  {
1534  d->m_screensaver->Restore();
1535  d->m_screensaverEnabled = true;
1536  }
1537 }
1538 
1540 {
1541  if (d->m_screensaver)
1542  {
1543  d->m_screensaver->Reset();
1544  d->m_screensaverEnabled = false;
1545  }
1546 }
1547 
1549 {
1550  return d->m_screensaverEnabled;
1551 }
1552 
1554 {
1555  if (!d->m_screensaver)
1556  return false;
1557 
1558  return d->m_screensaver->Asleep();
1559 }
1560 
1563 void MythUIHelper::SetX11Display(const QString &display)
1564 {
1565  x11_display = display;
1566 }
1567 
1569 {
1570  return x11_display;
1571 }
1572 
1573 void MythUIHelper::AddCurrentLocation(const QString& location)
1574 {
1575  QMutexLocker locker(&m_locationLock);
1576 
1577  if (m_currentLocation.isEmpty() || m_currentLocation.last() != location)
1578  m_currentLocation.push_back(location);
1579 }
1580 
1582 {
1583  QMutexLocker locker(&m_locationLock);
1584 
1585  if (m_currentLocation.isEmpty())
1586  return QString("UNKNOWN");
1587 
1588  return m_currentLocation.takeLast();
1589 }
1590 
1591 QString MythUIHelper::GetCurrentLocation(bool fullPath, bool mainStackOnly)
1592 {
1593  QString result;
1594  QMutexLocker locker(&m_locationLock);
1595 
1596  if (fullPath)
1597  {
1598  // get main stack top screen
1600  result = stack->GetLocation(true);
1601 
1602  if (!mainStackOnly)
1603  {
1604  // get popup stack main screen
1605  stack = GetMythMainWindow()->GetStack("popup stack");
1606 
1607  if (!stack->GetLocation(true).isEmpty())
1608  result += '/' + stack->GetLocation(false);
1609  }
1610 
1611  // if there's a location in the stringlist add that (non mythui screen or external app running)
1612  if (!m_currentLocation.isEmpty())
1613  {
1614  for (int x = 0; x < m_currentLocation.count(); x++)
1615  result += '/' + m_currentLocation[x];
1616  }
1617  }
1618  else
1619  {
1620  // get main stack top screen
1622  result = stack->GetLocation(false);
1623 
1624  if (!mainStackOnly)
1625  {
1626  // get popup stack top screen
1627  stack = GetMythMainWindow()->GetStack("popup stack");
1628 
1629  if (!stack->GetLocation(false).isEmpty())
1630  result = stack->GetLocation(false);
1631  }
1632 
1633  // if there's a location in the stringlist use that (non mythui screen or external app running)
1634  if (!m_currentLocation.isEmpty())
1635  result = m_currentLocation.last();
1636  }
1637 
1638  if (result.isEmpty())
1639  result = "UNKNOWN";
1640 
1641  return result;
1642 }
1643 
1645 {
1646  return d->m_imageThreadPool;
1647 }
1648 
1650 {
1651  return d->GetPixelAspectRatio();
1652 }
1653 
1654 QSize MythUIHelper::GetBaseSize(void) const
1655 {
1656  return {d->m_baseWidth, d->m_baseHeight};
1657 }
1658 
1660 {
1661  d->m_fontStretch = stretch;
1662 }
1663 
1665 {
1666  return d->m_fontStretch;
1667 }
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:152
void SetFontStretch(int stretch)
void Disable(void)
Definition: screensaver.cpp:56
static QString themedir
Definition: mythdirs.cpp:21
MythDisplay * m_display
void LoadQtConfig(void)
double GetPixelAspectRatio(void)
QPalette m_palette
Colour scheme.
static QString GetX11Display(void)
bool Load(MythImageReader *reader)
Definition: mythimage.cpp:271
ImageCacheMode
Definition: mythuihelper.h:24
static QFont GetMediumFont(void)
static void DisableScreensaver(void)
bool IsImageInCache(const QString &url)
ScreenSaverControl * m_screensaver
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 QString GetExtraScreenInfo(QScreen *qScreen)
QString GetThemeDir(void)
QScreen * GetCurrentScreen(void)
Return a pointer to the screen to use.
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:65
virtual bool UsingVideoModes(void)
Definition: mythdisplay.h:65
double GetPixelAspectRatio(void) const
QStringList GetThemeSearchPath(void)
MythUIHelperPrivate * d
Definition: mythuihelper.h:150
virtual MythScreenType * GetTopScreen(void) const
QStringList m_currentLocation
Definition: mythuihelper.h:153
void DoDisableScreensaver(void)
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 settings.
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
int GetScreenCount(void)
void GetScreenBounds(void)
Get screen size from Qt, respecting for user's multiple screen prefs.
static QMutex uiLock
QString RemoveCurrentLocation(void)
QAtomicInteger< qint64 > m_maxCacheSize
void IncludeInCacheSize(MythImage *im)
static QString x11_display
Definition: mythuihelper.h:122
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)
void GetScreenBounds(int &xbase, int &ybase, int &width, int &height)
bool SwitchToGUI(Mode NextMode=GUI, bool Wait=false)
Switches to the GUI resolution specified.
QString GetRemoteCacheDir(void)
Returns the directory for all files cached from the backend.
Definition: mythdirs.cpp:241
QMap< QString, MythImage * > m_imageCache
static bool SpanAllScreens(void)
Return true if the MythTV windows should span all screens.
MythUIMenuCallbacks * GetMenuCBs(void)
bool GetScreensaverEnabled(void)
void GetScreenSettings(float &wmult, float &hmult)
QAtomicInteger< qint64 > m_cacheSize
void RemoveFromCacheByFile(const QString &fname)
void ResetLanguage(void)