MythTV  master
mythdisplay.cpp
Go to the documentation of this file.
1 // Std
2 #include <algorithm>
3 
4 //Qt
5 #include <QTimer>
6 #include <QThread>
7 #include <QApplication>
8 #include <QElapsedTimer>
9 #include <QWindow>
10 
11 // MythTV
12 #include "libmythbase/compat.h"
15 #include "mythuihelper.h"
16 #include "mythdisplay.h"
17 #include "opengl/mythegl.h"
18 #include "mythmainwindow.h"
19 
20 #ifdef USING_DBUS
22 #endif
23 #ifdef USING_WAYLANDEXTRAS
25 #endif
26 #ifdef Q_OS_ANDROID
28 #endif
29 #ifdef Q_OS_DARWIN
31 #endif
32 #ifdef USING_X11
35 #endif
36 #ifdef USING_DRM
39 #endif
40 #if defined(Q_OS_WIN)
42 #endif
43 #ifdef USING_MMAL
45 #endif
46 
47 #define LOC QString("Display: ")
48 
84 {
85  MythDisplay* result = nullptr;
86 #ifdef USING_X11
88  result = new MythDisplayX11();
89 #endif
90 #ifdef USING_DBUS
91  // Disabled for now as org.gnome.Mutter.DisplayConfig.ApplyConfiguration does
92  // not seem to be actually implemented by anyone.
93 #ifdef USING_WAYLANDEXTRAS
94  //if (MythWaylandDevice::IsAvailable())
95 #endif
96  //{
97  // if (!result)
98  // result = MythDisplayMutter::Create();
99  //}
100 #endif
101 #ifdef USING_DRM
102  if (!result)
103  {
104  result = new MythDisplayDRM(MainWindow);
105  // On the Pi, use MythDisplayRPI if mode switching is not available via DRM
106 #ifdef USING_MMAL
107  if (!result->VideoModesAvailable())
108  {
109  delete result;
110  result = nullptr;
111  }
112 #endif
113  }
114 #else
115  (void)MainWindow;
116 #endif
117 #ifdef USING_MMAL
118  if (!result)
119  result = new MythDisplayRPI();
120 #endif
121 #ifdef Q_OS_DARWIN
122  if (!result)
123  result = new MythDisplayOSX();
124 #endif
125 #ifdef Q_OS_ANDROID
126  if (!result)
127  result = new MythDisplayAndroid();
128 #endif
129 #if defined(Q_OS_WIN)
130  if (!result)
131  result = new MythDisplayWindows();
132 #endif
133  if (!result)
134  result = new MythDisplay();
135  return result;
136 }
137 
139 {
140  QStringList result;
141  bool spanall = false;
142  int screencount = MythDisplay::GetScreenCount();
143  if (MythDisplay::SpanAllScreens() && screencount > 1)
144  {
145  spanall = true;
146  result.append(tr("Spanning %1 screens").arg(screencount));
147  result.append(tr("Total bounds") + QString("\t: %1x%2")
148  .arg(GetScreenBounds().width()).arg(GetScreenBounds().height()));
149  result.append("");
150  }
151 
152  if (m_hdrState)
153  {
154  auto types = m_hdrState->m_supportedTypes;
155  auto hdr = m_hdrState->TypesToString();
156  result.append(tr("Supported HDR formats\t: %1").arg(hdr.join(",")));
157  if (types && !m_hdrState->IsControllable())
158  result.append(tr("HDR mode switching is not available"));
159  if (auto brightness = m_hdrState->GetMaxLuminance(); brightness > 1.0)
160  result.append(tr("Max display brightness\t: %1 nits").arg(static_cast<int>(brightness)));
161  }
162 
163  if (m_vrrState)
164  {
165  result.append(tr("Variable refresh rate '%1': %2 %3")
166  .arg(m_vrrState->TypeToString(),
167  m_vrrState->Enabled() ? tr("Enabled") : tr("Disabled"),
168  m_vrrState->RangeDescription()));
169  }
170 
171  auto * current = GetCurrentScreen();
172  const auto screens = QGuiApplication::screens();
173  bool first = true;
174  for (auto *screen : qAsConst(screens))
175  {
176  if (!first)
177  result.append("");
178  first = false;
179  auto id = QString("(%1)").arg(screen->manufacturer());
180  if (screen == current && !spanall)
181  result.append(tr("Current screen %1 %2:").arg(screen->name(), id));
182  else
183  result.append(tr("Screen %1 %2:").arg(screen->name(), id));
184  result.append(tr("Size") + QString("\t\t: %1mmx%2mm")
185  .arg(screen->physicalSize().width()).arg(screen->physicalSize().height()));
186  if (screen == current)
187  {
188  QString source;
189  auto aspect = GetAspectRatio(source);
190  result.append(tr("Aspect ratio") + QString("\t: %1 (%2)")
191  .arg(aspect, 0, 'f', 3).arg(source));
192  if (!spanall)
193  {
194  result.append(tr("Current mode") + QString("\t: %1x%2@%3Hz")
195  .arg(GetResolution().width()).arg(GetResolution().height())
196  .arg(GetRefreshRate(), 0, 'f', 2));
197  const auto & modes = GetVideoModes();
198  if (!modes.empty())
199  {
200  result.append(tr("Available modes:"));
201  for (auto it = modes.crbegin(); it != modes.crend(); ++it)
202  result.append(" " + it->ToString());
203  }
204  }
205  }
206  }
207 
208  return result;
209 }
210 
212 {
214  DebugScreen(m_screen, "Using");
215  if (m_screen)
216  {
217  connect(m_screen, &QScreen::geometryChanged, this, &MythDisplay::GeometryChanged);
218  connect(m_screen, &QScreen::physicalDotsPerInchChanged, this, &MythDisplay::PhysicalDPIChanged);
219  }
220 
221  auto *guiapp = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
222  if (guiapp == nullptr)
223  return;
224 
225  connect(guiapp, &QGuiApplication::screenRemoved, this, &MythDisplay::ScreenRemoved);
226  connect(guiapp, &QGuiApplication::screenAdded, this, &MythDisplay::ScreenAdded);
227  connect(guiapp, &QGuiApplication::primaryScreenChanged, this, &MythDisplay::PrimaryScreenChanged);
228 }
229 
231 {
232  LOG(VB_GENERAL, LOG_INFO, LOC + "Deleting");
233 }
234 
248 void MythDisplay::SetWidget(QWidget *MainWindow)
249 {
250  QWidget* oldwidget = m_widget;
251  m_widget = MainWindow;
252  if (!m_modeComplete)
254 
255  QWindow* oldwindow = m_window;
256  if (m_widget)
257  m_window = m_widget->windowHandle();
258  else
259  m_window = nullptr;
260 
261  if (m_widget && (m_widget != oldwidget))
262  LOG(VB_GENERAL, LOG_INFO, LOC + "Have main widget");
263 
264  if (m_window && (m_window != oldwindow))
265  {
266  LOG(VB_GENERAL, LOG_INFO, LOC + "Have main window");
267 
268  connect(m_window, &QWindow::screenChanged, this, &MythDisplay::ScreenChanged, Qt::UniqueConnection);
269  QScreen *desired = GetDesiredScreen();
270  // If we have changed the video mode for the old screen then reset
271  // it to the default/desktop mode
272  if (oldwindow)
273  SwitchToDesktop();
274  // Ensure we completely re-initialise when the new screen is set
275  m_initialised = false;
276  if (desired != m_screen)
277  DebugScreen(desired, "Moving to");
278  m_window->setScreen(desired);
279  // WaitForNewScreen doesn't work as intended. It successfully filters
280  // out unwanted screenChanged signals after moving screens - but always
281  //times out. This just delays startup by 500ms - so ignore on startup as it isn't needed.
282  if (!m_firstScreenChange)
284  m_firstScreenChange = false;
286  return;
287  }
288 }
289 
291 {
292  return QGuiApplication::screens().size();
293 }
294 
296 {
297  if (m_physicalSize.isEmpty() || m_resolution.isEmpty())
298  return 1.0;
299 
300  return (m_physicalSize.width() / static_cast<double>(m_resolution.width())) /
301  (m_physicalSize.height() / static_cast<double>(m_resolution.height()));
302 }
303 
305 {
306  return m_guiMode.Resolution();
307 }
308 
310 {
311  return m_screenBounds;
312 }
313 
327 {
328  return m_screen;
329 }
330 
332 {
333  QScreen* newscreen = nullptr;
334 
335  // If geometry is overriden at the command line level, try and determine
336  // which screen that applies to (if any).
337  // N.B. So many potential issues here e.g. should the geometry override be
338  // ignored after first use? (as it will continue to override the screen
339  // regardless of changes to screen preference).
341  {
342  // this matches the check in MythMainWindow
343  bool windowed = GetMythDB()->GetBoolSetting("RunFrontendInWindow", false) &&
345  QRect override = MythMainWindow::GetGeometryOverride();
346  // When windowed, we use topleft as a best guess as to which screen we belong in.
347  // When fullscreen, Qt appears to use the reverse - though this may be
348  // the window manager rather than Qt. So could be wrong.
349  QPoint point = windowed ? override.topLeft() : override.bottomRight();
350  QList screens = QGuiApplication::screens();
351  for (QScreen *screen : qAsConst(screens))
352  {
353  if (screen->geometry().contains(point))
354  {
355  newscreen = screen;
356  LOG(VB_GENERAL, LOG_INFO, LOC + QString(
357  "Geometry override places window in screen '%1'").arg(newscreen->name()));
358  break;
359  }
360  }
361  }
362 
363  // If spanning all screens, then always use the primary display
364  if (!newscreen && MythDisplay::SpanAllScreens())
365  {
366  LOG(VB_GENERAL, LOG_INFO, LOC + "Using primary screen for multiscreen");
367  newscreen = QGuiApplication::primaryScreen();
368  }
369 
370  QString name = gCoreContext->GetSetting("XineramaScreen", nullptr);
371  // Lookup by name
372  if (!newscreen)
373  {
374  QList screens = QGuiApplication::screens();
375  for (QScreen *screen : qAsConst(screens))
376  {
377  if (!name.isEmpty() && name == screen->name())
378  {
379  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Found screen '%1'").arg(name));
380  newscreen = screen;
381  }
382  }
383  }
384 
385  // No name match. These were previously numbers.
386  if (!newscreen)
387  {
388  bool ok = false;
389  int screen_num = name.toInt(&ok);
390  QList<QScreen *>screens = QGuiApplication::screens();
391  if (ok && (screen_num >= 0) && (screen_num < screens.size()))
392  {
393  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Found screen number %1 (%2)")
394  .arg(name, screens[screen_num]->name()));
395  newscreen = screens[screen_num];
396  }
397  }
398 
399  // For anything else, return the primary screen.
400  if (!newscreen)
401  {
402  QScreen *primary = QGuiApplication::primaryScreen();
403  if (name.isEmpty() && primary)
404  {
405  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Defaulting to primary screen (%1)")
406  .arg(primary->name()));
407  }
408  else if (name != "-1" && primary)
409  {
410  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Screen '%1' not found, defaulting to primary screen (%2)")
411  .arg(name, primary->name()));
412  }
413  newscreen = primary;
414  }
415 
416  return newscreen;
417 }
418 
421 void MythDisplay::ScreenChanged(QScreen *qScreen)
422 {
423  if (qScreen == m_screen)
424  return;
425  if (m_screen)
426  disconnect(m_screen, nullptr, this, nullptr);
427  DebugScreen(qScreen, "Changed to");
428  m_screen = qScreen;
429  connect(m_screen, &QScreen::geometryChanged, this, &MythDisplay::GeometryChanged);
430  connect(m_screen, &QScreen::physicalDotsPerInchChanged, this, &MythDisplay::PhysicalDPIChanged);
431  Initialise();
432  emit CurrentScreenChanged(qScreen);
433 }
434 
436 {
437  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt screen pixel ratio changed to %1")
438  .arg(DPI, 2, 'f', 2, '0'));
439  emit CurrentDPIChanged(DPI);
440 }
441 
442 void MythDisplay::PrimaryScreenChanged(QScreen* qScreen)
443 {
444  DebugScreen(qScreen, "New primary");
445 }
446 
447 void MythDisplay::ScreenAdded(QScreen* qScreen)
448 {
449  DebugScreen(qScreen, "New");
450  emit ScreenCountChanged(QGuiApplication::screens().size());
451 }
452 
453 void MythDisplay::ScreenRemoved(QScreen* qScreen)
454 {
455  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Screen '%1' removed").arg(qScreen->name()));
456  emit ScreenCountChanged(QGuiApplication::screens().size());
457 }
458 
459 void MythDisplay::GeometryChanged(const QRect Geo)
460 {
461  LOG(VB_GENERAL, LOG_INFO, LOC + QString("New screen geometry: %1x%2+%3+%4")
462  .arg(Geo.width()).arg(Geo.height()).arg(Geo.left()).arg(Geo.top()));
463 }
464 
472 {
473  // Certain platform implementations do not have a window to access at startup
474  // and hence use this implementation. Flag the status as incomplete to ensure
475  // we try to retrieve the full details at the first opportunity.
476  m_modeComplete = false;
477  m_edid = MythEDID();
478  QScreen *screen = GetCurrentScreen();
479  if (!screen)
480  {
481  m_refreshRate = 60.0;
482  m_physicalSize = QSize(0, 0);
483  m_resolution = QSize(1920, 1080);
484  return;
485  }
486  m_refreshRate = screen->refreshRate();
487  m_resolution = screen->size();
488  m_physicalSize = QSize(static_cast<int>(screen->physicalSize().width()),
489  static_cast<int>(screen->physicalSize().height()));
490 }
491 
494 {
495  return gCoreContext->GetSetting("XineramaScreen", nullptr) == "-1";
496 }
497 
498 QString MythDisplay::GetExtraScreenInfo(QScreen *qScreen)
499 {
500  QString mfg = qScreen->manufacturer();
501  if (mfg.isEmpty())
502  mfg = "Unknown";
503  QString model = qScreen->model();
504  if (model.isEmpty())
505  model = "Unknown";
506  return QString("(Make: %1 Model: %2)").arg(mfg, model);
507 }
508 
509 void MythDisplay::DebugScreen(QScreen *qScreen, const QString &Message)
510 {
511  if (!qScreen)
512  return;
513 
514  auto geom = qScreen->geometry();
515  LOG(VB_GENERAL, LOG_INFO, LOC + QString("%1 screen '%2' %3")
516  .arg(Message, qScreen->name(), GetExtraScreenInfo(qScreen)));
517  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Qt screen pixel ratio: %1")
518  .arg(qScreen->devicePixelRatio(), 2, 'f', 2, '0'));
519  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Geometry: %1x%2+%3+%4 Size(Qt): %5mmx%6mm")
520  .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
521  .arg(qScreen->physicalSize().width()).arg(qScreen->physicalSize().height()));
522 
523  if (qScreen->virtualGeometry() != geom)
524  {
525  geom = qScreen->virtualGeometry();
526  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Total virtual geometry: %1x%2+%3+%4")
527  .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top()));
528  }
529 }
530 
532 {
533  m_videoModes.clear();
534  m_overrideVideoModes.clear();
536  // Note: The EDID is retrieved in UpdateCurrentMode and we need the EDID to
537  // check for refresh rate range support.
538  m_vrrState = MythVRR::Create(this);
540 
541  // Set the desktop mode - which is the mode at startup. We must always return
542  // the screen to this mode.
543  if (!m_initialised)
544  {
545  // Only ever set this once or after a screen change
546  m_initialised = true;
548  LOG(VB_GENERAL, LOG_NOTICE, LOC + QString("Desktop video mode: %1x%2 %3Hz")
549  .arg(m_resolution.width()).arg(m_resolution.height()).arg(m_refreshRate, 0, 'f', 3));
550  if (m_edid.Valid())
551  {
552  if (m_edid.IsSRGB())
553  LOG(VB_GENERAL, LOG_NOTICE, LOC + "Display is using sRGB colourspace");
554  else
555  LOG(VB_GENERAL, LOG_NOTICE, LOC + "Display has custom colourspace");
556 
557  InitHDR();
558  }
559  }
560 
561  // Set the gui mode from database settings
562  int pixelwidth = m_resolution.width();
563  int pixelheight = m_resolution.height();
564  int mmwidth = m_physicalSize.width();
565  int mmheight = m_physicalSize.height();
566  double refreshrate = m_refreshRate;
567  double aspectratio = 0.0;
568  GetMythDB()->GetResolutionSetting("GuiVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
569  GetMythDB()->GetResolutionSetting("DisplaySize", mmwidth, mmheight);
570  m_guiMode = MythDisplayMode(pixelwidth, pixelheight, mmwidth, mmheight, -1.0, refreshrate);
571 
572  // Set default video mode
573  pixelwidth = pixelheight = 0;
574  GetMythDB()->GetResolutionSetting("TVVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
575  m_videoMode = MythDisplayMode(pixelwidth, pixelheight, mmwidth, mmheight, aspectratio, refreshrate);
576 
577  // Initialise video override modes
578  for (int i = 0; true; ++i)
579  {
580  int iw = 0;
581  int ih = 0;
582  int ow = 0;
583  int oh = 0;
584  double iaspect = 0.0;
585  double oaspect = 0.0;
586  double irate = 0.0;
587  double orate = 0.0;
588 
589  GetMythDB()->GetResolutionSetting("VidMode", iw, ih, iaspect, irate, i);
590  GetMythDB()->GetResolutionSetting("TVVidMode", ow, oh, oaspect, orate, i);
591 
592  if ((!iw && !ih && qFuzzyIsNull(irate)) || !(ih && ow && oh))
593  break;
594 
595  uint64_t key = MythDisplayMode::CalcKey(QSize(iw, ih), irate);
596  MythDisplayMode scr(QSize(ow, oh), QSize(mmwidth, mmheight), oaspect, orate);
597  m_overrideVideoModes[key] = scr;
598  }
599 }
600 
601 
610 {
611  const auto screens = QGuiApplication::screens();
612  for (auto * screen : qAsConst(screens))
613  {
614  auto dim = screen->geometry();
615  auto extra = MythDisplay::GetExtraScreenInfo(screen);
616  LOG(VB_GUI, LOG_INFO, LOC + QString("Screen %1: %2x%3 %4")
617  .arg(screen->name()).arg(dim.width()).arg(dim.height()).arg(extra));
618  }
619 
620  const auto * primary = QGuiApplication::primaryScreen();
621  if (!primary)
622  {
623  if (!screens.empty())
624  primary = screens.front();
625  if (!primary)
626  {
627  LOG(VB_GENERAL, LOG_ERR, LOC + "Qt has no screens!");
628  return;
629  }
630  }
631 
632  LOG(VB_GUI, LOG_INFO, LOC +QString("Primary screen: %1.").arg(primary->name()));
633 
634  auto numScreens = MythDisplay::GetScreenCount();
635  auto dim = primary->virtualSize();
636  LOG(VB_GUI, LOG_INFO, LOC + QString("Total desktop dim: %1x%2, over %3 screen[s].")
637  .arg(dim.width()).arg(dim.height()).arg(numScreens));
638 
640  {
641  LOG(VB_GUI, LOG_INFO, LOC + QString("Using entire desktop."));
642  m_screenBounds = primary->virtualGeometry();
643  return;
644  }
645 
646  if (GetMythDB()->GetBoolSetting("RunFrontendInWindow", false))
647  {
648  LOG(VB_GUI, LOG_INFO, LOC + "Running in a window");
649  // This doesn't include the area occupied by the
650  // Windows taskbar, or the Mac OS X menu bar and Dock
651  m_screenBounds = m_screen->availableGeometry();
652  }
653  else
654  {
655  m_screenBounds = m_screen->geometry();
656  }
657 
658  LOG(VB_GUI, LOG_INFO, LOC + QString("Using screen %1: %2x%3 at %4+%5")
659  .arg(m_screen->name()).arg(m_screenBounds.width()).arg(m_screenBounds.height())
660  .arg(m_screenBounds.left()).arg(m_screenBounds.top()));
661 }
662 
670 {
671  return Size.width() > m_resolution.width() || Size.height() > m_resolution.height();
672 }
673 
679 {
681  if (current == m_desktopMode)
682  return;
684 }
685 
689 bool MythDisplay::SwitchToVideo(QSize Size, double Rate)
690 {
691  if (!m_modeComplete)
693 
696  double targetrate = 0.0;
697  double aspectoverride = 0.0;
698 
699  // try to find video override mode
701  Size.width(), Size.height(), Rate);
702 
703  if (key != 0)
704  {
705  next = m_overrideVideoModes[key];
706  if (next.AspectRatio() > 0.0)
707  aspectoverride = next.AspectRatio();
708  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Found custom screen override %1x%2 Aspect %3")
709  .arg(next.Width()).arg(next.Height()).arg(aspectoverride));
710  }
711 
712  // If requested refresh rate is 0, attempt to match video fps
713  if (qFuzzyIsNull(next.RefreshRate()))
714  {
715  LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("Trying to match best refresh rate %1Hz")
716  .arg(Rate, 0, 'f', 3));
717  next.SetRefreshRate(Rate);
718  }
719 
720  // need to change video mode?
721  (void)MythDisplayMode::FindBestMatch(GetVideoModes(), next, targetrate);
722 
723  // If GSync or FreeSync are enabled, ignore refresh rate only changes.
724  // N.B. This check is not used when switching to GUI (which already ignores
725  // rate only changes) or switching back to the desktop (where we must reset
726  // the display to the original state).
727  if (m_vrrState && m_vrrState->Enabled())
728  {
729  if (next.Resolution() == current.Resolution())
730  {
731  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Ignoring mode switch to %1Hz - VRR enabled")
732  .arg(Rate, 0, 'f', 3));
733  return true;
734  }
735  LOG(VB_GENERAL, LOG_INFO, LOC + "Allowing mode switch with VRR enabled for new resolution");
736  }
737 
738  // No need for change
739  if ((next == current) && (MythDisplayMode::CompareRates(current.RefreshRate(), targetrate)))
740  {
741  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using current mode %1x%2@%3Hz")
742  .arg(m_resolution.width()).arg(m_resolution.height()).arg(m_refreshRate));
743  return true;
744  }
745 
746  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Trying mode %1x%2@%3Hz")
747  .arg(next.Width()).arg(next.Height()).arg(next.RefreshRate(), 0, 'f', 3));
748 
749  if (!SwitchToVideoMode(next.Resolution(), targetrate))
750  {
751  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to change mode to %1x%2@%3Hz")
752  .arg(next.Width()).arg(next.Height()).arg(next.RefreshRate(), 0, 'f', 3));
753  return false;
754  }
755 
756  if (next.Resolution() != m_resolution)
758 
759  // N.B. We used a computed aspect ratio unless overridden
760  m_aspectRatioOverride = aspectoverride > 0.0 ? aspectoverride : 0.0;
762  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Switched to %1x%2@%3Hz for video %4x%5")
763  .arg(m_resolution.width()).arg(m_resolution.height())
764  .arg(m_refreshRate, 0, 'f', 3).arg(Size.width()).arg(Size.height()));
766  return true;
767 }
768 
772 {
773  if (!m_modeComplete)
775 
776  // If the current resolution is the same as the GUI resolution then do nothing
777  // as refresh rate should not be critical for the GUI.
779  {
780  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Using %1x%2@%3Hz for GUI")
781  .arg(m_resolution.width()).arg(m_resolution.height()).arg(m_refreshRate));
782  return true;
783  }
784 
786  {
787  LOG(VB_GENERAL, LOG_ERR, LOC + QString("Failed to change mode to %1x%2@%3Hz")
788  .arg(m_guiMode.Width()).arg(m_guiMode.Height()).arg(m_guiMode.RefreshRate(), 0, 'f', 3));
789  return false;
790  }
791 
792  if (Wait && (m_resolution != m_guiMode.Resolution()))
794 
796  m_aspectRatioOverride = 0.0;
797  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Switched to %1x%2@%3Hz")
798  .arg(m_resolution.width()).arg(m_resolution.height()).arg(m_refreshRate, 0, 'f', 3));
799  return true;
800 }
801 
803 {
804  return m_refreshRate;
805 }
806 
807 std::chrono::microseconds MythDisplay::GetRefreshInterval(std::chrono::microseconds Fallback) const
808 {
809  // If FreeSync or GSync are enabled, return the maximum refresh rate.
810  // N.B. This may need more work as the max may not be well defined - especially
811  // if the resolution is changing. Displays should however support at least 60Hz
812  // at all resolutions which should be fine in the vast majority of cases (as the
813  // only place the refresh interval is functionally important is in checking
814  // for double rate deinterlacing support).
815  if (m_vrrState && m_vrrState->Enabled())
816  {
817  const auto range = m_vrrState->GetRange();
818  auto max = std::get<1>(range) > 60 ? std::get<1>(range) : 60;
819  return microsecondsFromFloat(1000000.0 / max);
820  }
821 
822  if (m_refreshRate > 20.0 && m_refreshRate < 200.0)
823  return microsecondsFromFloat(1000000.0 / m_refreshRate);
824  if (Fallback > 33ms) // ~30Hz
825  Fallback /= 2;
826  return Fallback;
827 }
828 
830 {
831  auto targetrate = static_cast<double>(NAN);
832  const MythDisplayMode mode(Size, QSize(0, 0), -1.0, 0.0);
833  const auto & modes = GetVideoModes();
834  int match = MythDisplayMode::FindBestMatch(modes, mode, targetrate);
835  if (match < 0)
836  return {};
837  return modes[static_cast<size_t>(match)].RefreshRates();
838 }
839 
840 bool MythDisplay::SwitchToVideoMode(QSize /*Size*/, double /*Framerate*/)
841 {
842  return false;
843 }
844 
846 {
847  return m_videoModes;
848 }
849 
868 double MythDisplay::GetAspectRatio(QString &Source, bool IgnoreModeOverride)
869 {
870  auto valid = [](double Aspect) { return (Aspect > 0.1 && Aspect < 10.0); };
871 
872  // Override for this video mode
873  // Is this behaviour still needed?
874  if (!IgnoreModeOverride && valid(m_aspectRatioOverride))
875  {
876  Source = tr("Video mode override");
877  return m_aspectRatioOverride;
878  }
879 
880  // General override for invalid/misleading EDIDs or multiscreen setups
881  // New default of -1.0 equates to square pixels for modern displays
882  bool multiscreen = MythDisplay::SpanAllScreens() && GetScreenCount() > 1;
883  double override = gCoreContext->GetFloatSettingOnHost("XineramaMonitorAspectRatio",
884  gCoreContext->GetHostName(), -1.0);
885 
886  // Zero (not valid) indicates auto
887  if (valid(override))
888  {
889  Source = tr("Override");
890  return override;
891  }
892 
893  // Auto for multiscreen is a best guess
894  if (multiscreen)
895  {
896  double aspect = EstimateVirtualAspectRatio();
897  if (valid(aspect))
898  {
899  Source = tr("Multiscreen estimate");
900  return aspect;
901  }
902  }
903 
904  double calculated = m_resolution.isEmpty() ? 0.0 :
905  static_cast<double>(m_resolution.width()) / m_resolution.height();
906  double detected = m_physicalSize.isEmpty() ? 0.0 :
907  static_cast<double>(m_physicalSize.width()) / m_physicalSize.height();
908 
909  // Assume pixel aspect ratio is 1 (square pixels)
910  if (valid(calculated))
911  {
912  if ((override < 0.0) || !valid(detected))
913  {
914  Source = tr("Square pixels");
915  return calculated;
916  }
917  }
918 
919  // Based on actual physical size if available
920  if (valid(detected))
921  {
922  Source = tr("Detected");
923  return detected;
924  }
925 
926  // the aspect ratio of last resort
927  Source = tr("Guessed");
928  return 16.0 / 9.0;
929 }
930 
932 {
933  return m_edid;
934 }
935 
937 {
938  return m_hdrState;
939 }
940 
942 {
943  if (m_edid.Valid())
944  {
945  auto hdrdesc = m_edid.GetHDRSupport();
946  m_hdrState = MythHDR::Create(this, hdrdesc);
947  LOG(VB_GENERAL, LOG_NOTICE, LOC + QString("Supported HDR formats: %1")
948  .arg(m_hdrState->TypesToString().join(",")));
949  if (auto brightness = m_hdrState->GetMaxLuminance(); brightness > 1.0)
950  {
951  LOG(VB_GENERAL, LOG_NOTICE, LOC + QString("Display reports max brightness of %1 nits")
952  .arg(static_cast<int>(brightness)));
953  }
954  }
955 }
956 
967 {
968  auto sortscreens = [](const QScreen* First, const QScreen* Second)
969  {
970  if (First->geometry().left() < Second->geometry().left())
971  return true;
972  if (First->geometry().top() < Second->geometry().top())
973  return true;
974  return false;
975  };
976 
977  // default
978  double result = 16.0 / 9.0;
979 
980  QList<QScreen*> screens;
981  if (m_screen)
982  screens = m_screen->virtualSiblings();
983  if (screens.empty())
984  return result;
985 
986  // N.B. This sorting may not be needed
987  std::sort(screens.begin(), screens.end(), sortscreens);
988  QList<double> aspectratios;
989  QSize totalresolution;
990  int lasttop = 0;
991  int lastleft = 0;
992  int rows = 1;
993  int columns = 1;
994  for (auto it = screens.constBegin() ; it != screens.constEnd(); ++it)
995  {
996  QRect geom = (*it)->geometry();
997  totalresolution += geom.size();
998  LOG(VB_PLAYBACK, LOG_DEBUG, LOC + QString("%1x%2+%3+%4 %5")
999  .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
1000  .arg((*it)->physicalSize().width() / (*it)->physicalSize().height()));
1001  if (lastleft < geom.left())
1002  {
1003  columns++;
1004  lastleft = geom.left();
1005  }
1006  if (lasttop < geom.top())
1007  {
1008  rows++;
1009  lasttop = geom.top();
1010  lastleft = 0;
1011  }
1012  aspectratios << (*it)->physicalSize().width() / (*it)->physicalSize().height();
1013  }
1014 
1015  // If all else fails, use the total resolution and assume pixel aspect ratio
1016  // equals display aspect ratio
1017  if (!totalresolution.isEmpty())
1018  result = static_cast<double>(totalresolution.width()) / totalresolution.height();
1019 
1020  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Screen layout: %1x%2").arg(rows).arg(columns));
1021  if (rows == columns)
1022  {
1023  LOG(VB_GENERAL, LOG_DEBUG, LOC + "Grid layout");
1024  }
1025  else if (rows == 1 && columns > 1)
1026  {
1027  LOG(VB_GENERAL, LOG_DEBUG, LOC + "Horizontal layout");
1028  }
1029  else if (columns == 1 && rows > 1)
1030  {
1031  LOG(VB_GENERAL, LOG_DEBUG, LOC + "Vertical layout");
1032  }
1033  else
1034  {
1035  LOG(VB_GENERAL, LOG_INFO,
1036  LOC + QString("Unsupported layout - defaulting to %1 (%2/%3)")
1037  .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1038  return result;
1039  }
1040 
1041  // validate aspect ratios - with a little fuzzyness
1042  double aspectratio = 0.0;
1043  double average = 0.0;
1044  int count = 1;
1045  for (auto it2 = aspectratios.constBegin() ; it2 != aspectratios.constEnd(); ++it2, ++count)
1046  {
1047  aspectratio += *it2;
1048  average = aspectratio / count;
1049  if (qAbs(*it2 - average) > 0.1)
1050  {
1051  LOG(VB_GENERAL, LOG_INFO, LOC +
1052  QString("Inconsistent aspect ratios - defaulting to %1 (%2/%3)")
1053  .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1054  return result;
1055  }
1056  }
1057 
1058  aspectratio = (average * columns) / rows;
1059  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Estimated aspect ratio: %1")
1060  .arg(aspectratio));
1061  return aspectratio;
1062 }
1063 
1065 {
1066  return m_resolution;
1067 }
1068 
1070 {
1071  return m_physicalSize;
1072 }
1073 
1075 {
1076  // Some implementations may have their own mechanism for ensuring the mode
1077  // is updated before continuing
1078  if (!m_waitForModeChanges)
1079  return;
1080 
1081  LOG(VB_GENERAL, LOG_INFO, LOC + "Waiting for resolution change");
1082  QEventLoop loop;
1083  QTimer timer;
1084  timer.setSingleShot(true);
1085  connect(&timer, &QTimer::timeout, [](){ LOG(VB_GENERAL, LOG_WARNING, LOC + "Timed out wating for screen change"); });
1086  QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
1087  QObject::connect(m_screen, &QScreen::geometryChanged, &loop, &QEventLoop::quit);
1088  // 500ms maximum wait
1089  timer.start(500ms);
1090  loop.exec();
1091 }
1092 
1094 {
1095  // N.B. This isn't working as intended as it always times out rather than
1096  // exiting deliberately. It does however somehow filter out unwanted screenChanged
1097  // events that otherwise often put the widget in the wrong screen.
1098  // Needs more investigation - but for now it works:)
1099  if (!m_widget || !m_widget->windowHandle())
1100  return;
1101  LOG(VB_GENERAL, LOG_INFO, LOC + "Waiting for new screen");
1102  QEventLoop loop;
1103  QTimer timer;
1104  timer.setSingleShot(true);
1105  connect(&timer, &QTimer::timeout, [](){ LOG(VB_GENERAL, LOG_WARNING, LOC + "Timed out waiting for new screen"); });
1106  QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
1107  QObject::connect(m_widget->windowHandle(), &QWindow::screenChanged, &loop, &QEventLoop::quit);
1108  // 500ms maximum wait
1109  timer.start(500ms);
1110  loop.exec();
1111 }
1112 
1114 {
1115  int pauselengthinms = gCoreContext->GetNumSetting("VideoModeChangePauseMS", 0);
1116  if (pauselengthinms)
1117  {
1118  LOG(VB_GENERAL, LOG_INFO, LOC +
1119  QString("Pausing %1ms for video mode switch").arg(pauselengthinms));
1120  QEventLoop loop;
1121  QTimer timer;
1122  timer.setSingleShot(true);
1123  QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit);
1124  // 500ms maximum wait
1125  timer.start(pauselengthinms);
1126  loop.exec();
1127  }
1128 }
1129 
1131 {
1132  // This is intentionally formatted to match the output of xrandr for comparison
1133  if (VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_INFO))
1134  {
1135  LOG(VB_PLAYBACK, LOG_INFO, LOC + "Available modes:");
1136  for (auto it = m_videoModes.crbegin(); it != m_videoModes.crend(); ++it)
1137  {
1138  auto rates = (*it).RefreshRates();
1139  QStringList rateslist;
1140  for (auto it2 = rates.crbegin(); it2 != rates.crend(); ++it2)
1141  rateslist.append(QString("%1").arg(*it2, 2, 'f', 2, '0'));
1142  if (rateslist.empty())
1143  rateslist.append("Variable rate?");
1144  LOG(VB_PLAYBACK, LOG_INFO, QString("%1x%2\t%3")
1145  .arg((*it).Width()).arg((*it).Height()).arg(rateslist.join("\t")));
1146  }
1147  }
1148 }
1149 
1155 void MythDisplay::ConfigureQtGUI(int SwapInterval, const MythCommandLineParser& CmdLine)
1156 {
1157  auto forcevrr = CmdLine.toBool("vrr");
1158  bool gsyncchanged = false;
1159  bool freesyncchanged = false;
1160 
1161 #ifdef USING_QTWEBENGINE
1162  QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
1163 #endif
1164 
1165  // Set the default surface format. Explicitly required on some platforms.
1166  QSurfaceFormat format;
1167  // Allow overriding the default depth - use with caution as Qt will likely
1168  // crash if it cannot find a matching visual.
1169  if (qEnvironmentVariableIsSet("MYTHTV_DEPTH"))
1170  {
1171  // Note: Don't set depth and stencil to give Qt as much flexibility as possible
1172  int depth = std::clamp(qEnvironmentVariableIntValue("MYTHTV_DEPTH"), 6, 16);
1173  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Trying to force depth to '%1'").arg(depth));
1174  format.setRedBufferSize(depth);
1175  }
1176  else
1177  {
1178  format.setDepthBufferSize(0);
1179  format.setStencilBufferSize(0);
1180  }
1181  format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
1182  format.setProfile(QSurfaceFormat::CompatibilityProfile);
1183  format.setSwapInterval(SwapInterval);
1184  QSurfaceFormat::setDefaultFormat(format);
1185 
1186 #ifdef Q_OS_DARWIN
1187  // Without this, we can't set focus to any of the CheckBoxSetting, and most
1188  // of the MythPushButton widgets, and they don't use the themed background.
1189  QApplication::setDesktopSettingsAware(false);
1190 #endif
1191 
1192 #if defined (USING_DRM) && defined (USING_QTPRIVATEHEADERS)
1193  // Avoid trying to setup DRM if we are definitely not going to use it.
1194 #ifdef USING_X11
1196 #endif
1197  {
1198 #ifdef USING_WAYLANDEXTRAS
1199  // When vt switching this still detects wayland servers, so disabled for now
1200  //if (!MythWaylandDevice::IsAvailable())
1201 #endif
1202  {
1203  MythDRMDevice::SetupDRM(CmdLine);
1204  freesyncchanged = MythDRMVRR::s_freeSyncResetOnExit;
1205  }
1206  }
1207 #endif
1208 
1209 #if defined (Q_OS_LINUX) && defined (USING_EGL) && defined (USING_X11)
1210  // We want to use EGL for VAAPI/MMAL/DRMPRIME rendering to ensure we
1211  // can use zero copy video buffers for the best performance.
1212  // To force Qt to use EGL we must set 'QT_XCB_GL_INTEGRATION' to 'xcb_egl'
1213  // and this must be done before any GUI is created. If the platform plugin is
1214  // not xcb then this should have no effect.
1215  // This does however break when using NVIDIA drivers - which do not support
1216  // EGL like other drivers so we try to check the EGL vendor - and we currently
1217  // have no need for EGL with NVIDIA (that may change however).
1218  // NOTE force using EGL by setting MYTHTV_FORCE_EGL
1219  // NOTE disable using EGL by setting MYTHTV_NO_EGL
1220  // NOTE We have no Qt platform information, window/surface or logging when this is called.
1221  QString soft = qgetenv("LIBGL_ALWAYS_SOFTWARE");
1222  bool ignore = soft == "1" || soft.compare("true", Qt::CaseInsensitive) == 0;
1223  bool allow = qEnvironmentVariableIsEmpty("MYTHTV_NO_EGL") && !ignore;
1224  bool force = !qEnvironmentVariableIsEmpty("MYTHTV_FORCE_EGL");
1225  if ((force || allow) && MythDisplayX11::IsAvailable())
1226  {
1227  // N.B. By default, ignore EGL if vendor string is not returned
1228  QString vendor = MythEGL::GetEGLVendor();
1229  if (vendor.contains("nvidia", Qt::CaseInsensitive) && !force)
1230  {
1231  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Not requesting EGL for vendor '%1'").arg(vendor));
1232  }
1233  else if (!vendor.isEmpty() || force)
1234  {
1235  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Requesting EGL for vendor '%1'").arg(vendor));
1236  setenv("QT_XCB_GL_INTEGRATION", "xcb_egl", 0);
1237  }
1238  }
1239 #endif
1240 
1241 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1242  // Ignore desktop scaling
1243  QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
1244 #endif
1245 
1246 #ifdef USING_X11
1247  if (auto display = CmdLine.toString("display"); !display.isEmpty())
1249  // GSync support via libXNVCtrl
1250  // Note: FreeSync support is checked in MythDRMDevice::SetupDRM
1251  if (forcevrr)
1252  {
1253  MythGSync::ForceGSync(CmdLine.toUInt("vrr") > 0);
1254  gsyncchanged = MythGSync::s_gsyncResetOnExit;
1255  }
1256 #endif
1257 
1258  if (forcevrr && !(gsyncchanged || freesyncchanged))
1259  LOG(VB_GENERAL, LOG_INFO, LOC + "Variable refresh rate not adjusted");
1260 }
MythDisplay::m_physicalSize
QSize m_physicalSize
Definition: mythdisplay.h:93
mythwaylandextras.h
mythdisplaymutter.h
MythHDRPtr
std::shared_ptr< class MythHDR > MythHDRPtr
Definition: mythhdr.h:30
MythDisplayMode::AspectRatio
double AspectRatio() const
Definition: mythdisplaymode.cpp:84
MythDisplay::GetRefreshRate
double GetRefreshRate() const
Definition: mythdisplay.cpp:802
hardwareprofile.smolt.timeout
float timeout
Definition: smolt.py:103
MythDisplay::GetScreenBounds
QRect GetScreenBounds()
Definition: mythdisplay.cpp:309
MythDisplay::GetEDID
MythEDID & GetEDID()
Definition: mythdisplay.cpp:931
MythCommandLineParser
Parent class for defining application command line parsers.
Definition: mythcommandlineparser.h:116
MythDisplay::SwitchToDesktop
void SwitchToDesktop()
Return the screen to the original desktop video mode.
Definition: mythdisplay.cpp:678
MythDisplay::m_screenBounds
QRect m_screenBounds
Definition: mythdisplay.h:108
MythDisplay::m_hdrState
MythHDRPtr m_hdrState
Definition: mythdisplay.h:99
MythDisplayMode::FindBestScreen
static uint64_t FindBestScreen(const DisplayModeMap &Map, int Width, int Height, double Rate)
Definition: mythdisplaymode.cpp:225
MythDisplay::DebugScreen
static void DebugScreen(QScreen *qScreen, const QString &Message)
Definition: mythdisplay.cpp:509
MythDisplay::GeometryChanged
static void GeometryChanged(QRect Geometry)
Definition: mythdisplay.cpp:459
mythdisplaywindows.h
MythDisplay::m_resolution
QSize m_resolution
Definition: mythdisplay.h:92
MythDisplay::ScreenChanged
virtual void ScreenChanged(QScreen *qScreen)
The actual screen in use has changed. We must use it.
Definition: mythdisplay.cpp:421
MythDisplayDRM
Definition: mythdisplaydrm.h:11
MythDisplayModes
std::vector< MythDisplayMode > MythDisplayModes
Definition: mythdisplaymode.h:18
MythDisplay::m_videoMode
MythDisplayMode m_videoMode
Definition: mythdisplay.h:111
MythDisplayMode::CalcKey
static uint64_t CalcKey(QSize Size, double Rate)
Definition: mythdisplaymode.cpp:127
VERBOSE_LEVEL_CHECK
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
microsecondsFromFloat
std::enable_if_t< std::is_floating_point_v< T >, std::chrono::microseconds > microsecondsFromFloat(T value)
Helper function for convert a floating point number to a duration.
Definition: mythchrono.h:102
setenv
#define setenv(x, y, z)
Definition: compat.h:87
MythDisplayX11::IsAvailable
static bool IsAvailable()
Definition: mythdisplayx11.cpp:16
types
static const struct wl_interface * types[]
Definition: idle_inhibit_unstable_v1.c:39
MythDisplay::GetAspectRatio
double GetAspectRatio(QString &Source, bool IgnoreModeOverride=false)
Returns current screen aspect ratio.
Definition: mythdisplay.cpp:868
LOC
#define LOC
Definition: mythdisplay.cpp:47
MythDisplay::SpanAllScreens
static bool SpanAllScreens()
Return true if the MythTV windows should span all screens.
Definition: mythdisplay.cpp:493
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythDisplayRPI
Definition: mythdisplayrpi.h:16
MythDisplay::GetCurrentScreen
QScreen * GetCurrentScreen()
Return a pointer to the screen to use.
Definition: mythdisplay.cpp:326
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:50
MythDisplay::ScreenRemoved
void ScreenRemoved(QScreen *qScreen)
Definition: mythdisplay.cpp:453
force
bool force
Definition: mythcommflag.cpp:70
MythDisplay::GetPixelAspectRatio
double GetPixelAspectRatio()
Definition: mythdisplay.cpp:295
MythDisplay::PhysicalDPIChanged
void PhysicalDPIChanged(qreal DPI)
Definition: mythdisplay.cpp:435
MythDisplay::UpdateCurrentMode
virtual void UpdateCurrentMode()
Retrieve screen details.
Definition: mythdisplay.cpp:471
MythDisplay::InitScreenBounds
void InitScreenBounds()
Get screen size from Qt while respecting the user's multiscreen settings.
Definition: mythdisplay.cpp:609
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
MythDisplay::m_modeComplete
bool m_modeComplete
Definition: mythdisplay.h:89
MythDisplay::CurrentScreenChanged
void CurrentScreenChanged(QScreen *qScreen)
MythDisplay::GetHDRState
MythHDRPtr GetHDRState()
Definition: mythdisplay.cpp:936
MythDisplay::ConfigureQtGUI
static void ConfigureQtGUI(int SwapInterval, const MythCommandLineParser &CmdLine)
Shared static initialistaion code for all MythTV GUI applications.
Definition: mythdisplay.cpp:1155
MythDisplay::m_guiMode
MythDisplayMode m_guiMode
Definition: mythdisplay.h:110
mythdisplayosx.h
MythDisplay::DebugModes
void DebugModes() const
Definition: mythdisplay.cpp:1130
MythDisplay::GetGUIResolution
QSize GetGUIResolution()
Definition: mythdisplay.cpp:304
quit
@ quit
Definition: lirc_client.h:30
MythDisplayAndroid
Definition: mythdisplayandroid.h:7
MythEGL::GetEGLVendor
static QString GetEGLVendor(void)
Definition: mythegl.cpp:85
MythDisplay::PauseForModeSwitch
static void PauseForModeSwitch()
Definition: mythdisplay.cpp:1113
MythDisplay::m_aspectRatioOverride
double m_aspectRatioOverride
Definition: mythdisplay.h:91
mythdisplay.h
MythDisplay::GetResolution
QSize GetResolution()
Definition: mythdisplay.cpp:1064
MythDisplay::EstimateVirtualAspectRatio
double EstimateVirtualAspectRatio()
Estimate the overall display aspect ratio for multi screen setups.
Definition: mythdisplay.cpp:966
mythlogging.h
mythdisplayrpi.h
MythDisplay::WaitForNewScreen
void WaitForNewScreen()
Definition: mythdisplay.cpp:1093
Source
Definition: channelsettings.cpp:69
MythDisplay::~MythDisplay
~MythDisplay() override
Definition: mythdisplay.cpp:230
MythDRMVRR::s_freeSyncResetOnExit
static bool s_freeSyncResetOnExit
Definition: mythdrmvrr.h:11
MythDisplay::m_overrideVideoModes
DisplayModeMap m_overrideVideoModes
Definition: mythdisplay.h:112
mythdisplaydrm.h
MythDisplay::GetScreenCount
static int GetScreenCount()
Definition: mythdisplay.cpp:290
MythDisplay::GetExtraScreenInfo
static QString GetExtraScreenInfo(QScreen *qScreen)
Definition: mythdisplay.cpp:498
MythDisplayWindows
Definition: mythdisplaywindows.h:7
compat.h
MythDisplay::m_edid
MythEDID m_edid
Definition: mythdisplay.h:94
MythDisplay::m_window
QWindow * m_window
Definition: mythdisplay.h:96
MythEDID::GetHDRSupport
MythHDRDesc GetHDRSupport() const
Definition: mythedid.cpp:99
MythEDID::Valid
bool Valid() const
Definition: mythedid.cpp:39
MythDisplay::SetWidget
void SetWidget(QWidget *MainWindow)
Set the QWidget and QWindow in use.
Definition: mythdisplay.cpp:248
MythDisplay::SwitchToVideoMode
virtual bool SwitchToVideoMode(QSize Size, double Framerate)
Definition: mythdisplay.cpp:840
MythDisplayX11
Definition: mythdisplayx11.h:16
MythDisplay::SwitchToVideo
bool SwitchToVideo(QSize Size, double Rate=0.0)
Switches to the resolution and refresh rate defined in the database for the specified video resolutio...
Definition: mythdisplay.cpp:689
MythDisplay::GetPhysicalSize
QSize GetPhysicalSize()
Definition: mythdisplay.cpp:1069
MythVRR::Create
static MythVRRPtr Create(class MythDisplay *MDisplay)
Create a concrete implementation of MythVRR suitable for the given Display.
Definition: mythvrr.cpp:56
MythCommandLineParser::toUInt
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2250
MythDisplay::GetRefreshInterval
std::chrono::microseconds GetRefreshInterval(std::chrono::microseconds Fallback) const
Definition: mythdisplay.cpp:807
MythDisplay::m_waitForModeChanges
bool m_waitForModeChanges
Definition: mythdisplay.h:88
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
MythDisplay::m_videoModes
MythDisplayModes m_videoModes
Definition: mythdisplay.h:98
MythDisplay::GetRefreshRates
MythDisplayRates GetRefreshRates(QSize Size)
Definition: mythdisplay.cpp:829
MythDisplay
Definition: mythdisplay.h:22
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:910
MythEDID::IsSRGB
bool IsSRGB() const
Definition: mythedid.cpp:74
MythXDisplay::SetQtX11Display
static void SetQtX11Display(const QString &DisplayStr)
Definition: mythxdisplay.cpp:37
MythDisplayMode
Definition: mythdisplaymode.h:22
MythDisplay::ScreenAdded
void ScreenAdded(QScreen *qScreen)
Definition: mythdisplay.cpp:447
mythuihelper.h
MythDisplayMode::Height
int Height() const
Definition: mythdisplaymode.cpp:64
MythDisplayRates
std::vector< double > MythDisplayRates
Definition: mythdisplaymode.h:20
MythDisplay::GetVideoModes
virtual const MythDisplayModes & GetVideoModes()
Definition: mythdisplay.cpp:845
MythDisplay::m_refreshRate
double m_refreshRate
Definition: mythdisplay.h:90
MythDisplay::Initialise
void Initialise()
Definition: mythdisplay.cpp:531
MythDisplay::NextModeIsLarger
bool NextModeIsLarger(QSize Size)
Check whether the next mode is larger in size than the current mode.
Definition: mythdisplay.cpp:669
MythUIScreenBounds::WindowIsAlwaysFullscreen
static bool WindowIsAlwaysFullscreen()
Return true if the current platform only supports fullscreen windows.
Definition: mythuiscreenbounds.cpp:115
MythDisplay::m_widget
QWidget * m_widget
Definition: mythdisplay.h:95
MythCommandLineParser::toString
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
Definition: mythcommandlineparser.cpp:2358
mythcorecontext.h
MythCommandLineParser::toBool
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
Definition: mythcommandlineparser.cpp:2201
MythDisplay::SwitchToGUI
bool SwitchToGUI(bool Wait=false)
Switches to the GUI resolution.
Definition: mythdisplay.cpp:771
MythDisplay::ScreenCountChanged
void ScreenCountChanged(int Screens)
MythDisplayOSX
Definition: mythdisplayosx.h:10
MythDisplayMode::SetRefreshRate
void SetRefreshRate(double Rate)
Definition: mythdisplaymode.cpp:121
MythUIScreenBounds::GetGeometryOverride
static QRect GetGeometryOverride()
Definition: mythuiscreenbounds.cpp:25
MythDisplay::WaitForScreenChange
void WaitForScreenChange()
Definition: mythdisplay.cpp:1074
MythDisplayMode::RefreshRate
double RefreshRate() const
Definition: mythdisplaymode.cpp:95
mythdrmvrr.h
MythDisplayMode::CompareRates
static bool CompareRates(double First, double Second, double Precision=0.01)
Determine whether two rates are considered equal with the given precision.
Definition: mythdisplaymode.cpp:135
MythDisplay::m_initialised
bool m_initialised
Definition: mythdisplay.h:106
MythDisplay::m_screen
QScreen * m_screen
Definition: mythdisplay.h:97
mythegl.h
MythHDR::Create
static MythHDRPtr Create(class MythDisplay *MDisplay, const MythHDRDesc &Desc)
Definition: mythhdr.cpp:29
MythDisplay::m_desktopMode
MythDisplayMode m_desktopMode
Definition: mythdisplay.h:109
MythCoreContext::GetHostName
QString GetHostName(void)
Definition: mythcorecontext.cpp:836
mythdisplayandroid.h
MythDisplayMode::Resolution
QSize Resolution() const
Definition: mythdisplaymode.cpp:54
mythnvcontrol.h
MythDisplay::GetDescription
QStringList GetDescription()
Definition: mythdisplay.cpp:138
MythDisplay::GetDesiredScreen
static QScreen * GetDesiredScreen()
Definition: mythdisplay.cpp:331
MythDisplayMode::FindBestMatch
static int FindBestMatch(const MythDisplayModes &Modes, const MythDisplayMode &Mode, double &TargetRate)
Definition: mythdisplaymode.cpp:140
MythDisplay::PrimaryScreenChanged
static void PrimaryScreenChanged(QScreen *qScreen)
Definition: mythdisplay.cpp:442
MythDisplayMode::Width
int Width() const
Definition: mythdisplaymode.cpp:59
MythDisplay::m_vrrState
MythVRRPtr m_vrrState
Definition: mythdisplay.h:100
mythdisplayx11.h
MythDisplay::VideoModesAvailable
virtual bool VideoModesAvailable()
Definition: mythdisplay.h:29
MythGSync::s_gsyncResetOnExit
static bool s_gsyncResetOnExit
Definition: mythnvcontrol.h:26
mythmainwindow.h
MythDisplay::MythDisplay
MythDisplay()
Definition: mythdisplay.cpp:211
MythDisplay::Create
static MythDisplay * Create(MythMainWindow *MainWindow)
Create a MythDisplay object appropriate for the current platform.
Definition: mythdisplay.cpp:83
MythMainWindow
Definition: mythmainwindow.h:28
MythCoreContext::GetFloatSettingOnHost
double GetFloatSettingOnHost(const QString &key, const QString &host, double defaultval=0.0)
Definition: mythcorecontext.cpp:950
MythDisplay::InitHDR
void InitHDR()
Definition: mythdisplay.cpp:941
MythUIScreenBounds::GeometryIsOverridden
static bool GeometryIsOverridden()
Definition: mythuiscreenbounds.cpp:20
MythGSync::ForceGSync
static void ForceGSync(bool Enable)
Enable or disable GSync before the main window is created.
Definition: mythnvcontrol.cpp:27
MythEDID
Definition: mythedid.h:21
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:896
MythDisplay::CurrentDPIChanged
void CurrentDPIChanged(qreal DPI)
MythDisplay::m_firstScreenChange
bool m_firstScreenChange
Definition: mythdisplay.h:107