8#include <QElapsedTimer>
14#include <QQuickWindow>
29#if CONFIG_WAYLANDEXTRAS
54#define LOC QString("Display: ")
100#if CONFIG_WAYLANDEXTRAS
146 bool spanall =
false;
151 result.append(tr(
"Spanning %1 screens").arg(screencount));
152 result.append(tr(
"Total bounds") + QString(
"\t: %1x%2")
161 result.append(tr(
"Supported HDR formats\t: %1").arg(hdr.join(
",")));
163 result.append(tr(
"HDR mode switching is not available"));
164 if (
auto brightness =
m_hdrState->GetMaxLuminance(); brightness > 1.0)
165 result.append(tr(
"Max display brightness\t: %1 nits").arg(
static_cast<int>(brightness)));
170 result.append(tr(
"Variable refresh rate '%1': %2 %3")
172 m_vrrState->Enabled() ? tr(
"Enabled") : tr(
"Disabled"),
177 const auto screens = QGuiApplication::screens();
179 for (
auto *screen : std::as_const(screens))
184 auto id = QString(
"(%1)").arg(screen->manufacturer());
185 if (screen ==
current && !spanall)
186 result.append(tr(
"Current screen\t: %1 %2").arg(screen->name(),
id));
188 result.append(tr(
"Screen\t\t: %1 %2").arg(screen->name(),
id));
189 result.append(tr(
"Size") + QString(
"\t\t: %1mmx%2mm")
190 .arg(screen->physicalSize().width()).arg(screen->physicalSize().height()));
195 result.append(tr(
"Aspect ratio") + QString(
"\t: %1 (%2)")
196 .arg(aspect, 0,
'f', 3).arg(source));
199 result.append(tr(
"Current mode") + QString(
"\t: %1x%2@%3Hz")
205 result.append(tr(
"Available modes:"));
206 for (
auto it = modes.crbegin(); it != modes.crend(); ++it)
207 result.append(
" " + it->ToString());
217 : m_screen(GetDesiredScreen())
226 auto *guiapp = qobject_cast<QGuiApplication *>(QCoreApplication::instance());
227 if (guiapp ==
nullptr)
237 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Deleting");
267 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Have main widget");
271 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Have main window");
297 return QGuiApplication::screens().size();
342 QScreen* newscreen =
nullptr;
352 bool windowed =
GetMythDB()->GetBoolSetting(
"RunFrontendInWindow",
false) &&
358 QPoint point = windowed ?
override.topLeft() :
override.bottomRight();
359 QList screens = QGuiApplication::screens();
360 for (QScreen *screen : std::as_const(screens))
362 if (screen->geometry().contains(point))
365 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
366 "Geometry override places window in screen '%1'").arg(newscreen->name()));
375 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Using primary screen for multiscreen");
376 newscreen = QGuiApplication::primaryScreen();
383 QList screens = QGuiApplication::screens();
384 for (QScreen *screen : std::as_const(screens))
386 if (!name.isEmpty() && name == screen->name())
388 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found screen '%1'").arg(name));
398 int screen_num = name.toInt(&ok);
399 QList<QScreen *>screens = QGuiApplication::screens();
400 if (ok && (screen_num >= 0) && (screen_num < screens.size()))
402 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Found screen number %1 (%2)")
403 .arg(name, screens[screen_num]->name()));
404 newscreen = screens[screen_num];
411 QScreen *primary = QGuiApplication::primaryScreen();
412 if (name.isEmpty() && primary)
414 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Defaulting to primary screen (%1)")
415 .arg(primary->name()));
417 else if (name !=
"-1" && primary)
419 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen '%1' not found, defaulting to primary screen (%2)")
420 .arg(name, primary->name()));
435 disconnect(
m_screen,
nullptr,
this,
nullptr);
446 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Qt screen pixel ratio changed to %1")
447 .arg(DPI, 2,
'f', 2,
'0'));
464 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen '%1' removed").arg(qScreen->name()));
470 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"New screen geometry: %1x%2+%3+%4")
471 .arg(Geo.width()).arg(Geo.height()).arg(Geo.left()).arg(Geo.top()));
497 m_physicalSize = QSize(
static_cast<int>(screen->physicalSize().width()),
498 static_cast<int>(screen->physicalSize().height()));
509 QString mfg = qScreen->manufacturer();
512 QString model = qScreen->model();
515 return QString(
"(Make: %1 Model: %2)").arg(mfg, model);
523 auto geom = qScreen->geometry();
524 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"%1 screen '%2' %3")
526 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Qt screen pixel ratio: %1")
527 .arg(qScreen->devicePixelRatio(), 2,
'f', 2,
'0'));
528 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Geometry: %1x%2+%3+%4 Size(Qt): %5mmx%6mm")
529 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
530 .arg(qScreen->physicalSize().width()).arg(qScreen->physicalSize().height()));
532 if (qScreen->virtualGeometry() != geom)
534 geom = qScreen->virtualGeometry();
535 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Total virtual geometry: %1x%2+%3+%4")
536 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top()));
557 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Desktop video mode: %1x%2 %3Hz")
562 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Display is using sRGB colourspace");
564 LOG(VB_GENERAL, LOG_NOTICE,
LOC +
"Display has custom colourspace");
576 double aspectratio = 0.0;
577 GetMythDB()->GetResolutionSetting(
"GuiVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
578 GetMythDB()->GetResolutionSetting(
"DisplaySize", mmwidth, mmheight);
582 pixelwidth = pixelheight = 0;
583 GetMythDB()->GetResolutionSetting(
"TVVidMode", pixelwidth, pixelheight, aspectratio, refreshrate);
587 for (
int i = 0;
true; ++i)
593 double iaspect = 0.0;
594 double oaspect = 0.0;
598 GetMythDB()->GetResolutionSetting(
"VidMode", iw, ih, iaspect, irate, i);
599 GetMythDB()->GetResolutionSetting(
"TVVidMode", ow, oh, oaspect, orate, i);
601 if ((!iw && !ih && qFuzzyIsNull(irate)) || !(ih && ow && oh))
605 MythDisplayMode scr(QSize(ow, oh), QSize(mmwidth, mmheight), oaspect, orate);
620 const auto screens = QGuiApplication::screens();
621 for (
auto * screen : std::as_const(screens))
623 auto dim = screen->geometry();
625 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Screen %1: %2x%3 %4")
626 .arg(screen->name()).arg(dim.width()).arg(dim.height()).arg(extra));
629 const auto * primary = QGuiApplication::primaryScreen();
632 if (!screens.empty())
633 primary = screens.front();
636 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Qt has no screens!");
641 LOG(VB_GUI, LOG_INFO,
LOC +QString(
"Primary screen: %1.").arg(primary->name()));
644 auto dim = primary->virtualSize();
645 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Total desktop dim: %1x%2, over %3 screen[s].")
646 .arg(dim.width()).arg(dim.height()).arg(numScreens));
650 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Using entire desktop."));
655 if (!
GetMythDB()->GetBoolSetting(
"ForceFullScreen",
false) &&
656 GetMythDB()->GetBoolSetting(
"RunFrontendInWindow",
false))
658 LOG(VB_GUI, LOG_INFO,
LOC +
"Running in a window");
668 LOG(VB_GUI, LOG_INFO,
LOC + QString(
"Using screen %1: %2x%3 at %4+%5")
706 double targetrate = 0.0;
707 double aspectoverride = 0.0;
711 Size.width(), Size.height(), Rate);
718 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Found custom screen override %1x%2 Aspect %3")
719 .arg(next.
Width()).arg(next.
Height()).arg(aspectoverride));
725 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"Trying to match best refresh rate %1Hz")
726 .arg(Rate, 0,
'f', 3));
741 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Ignoring mode switch to %1Hz - VRR enabled")
742 .arg(Rate, 0,
'f', 3));
745 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Allowing mode switch with VRR enabled for new resolution");
751 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using current mode %1x%2@%3Hz")
756 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Trying mode %1x%2@%3Hz")
761 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to change mode to %1x%2@%3Hz")
772 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switched to %1x%2@%3Hz for video %4x%5")
774 .arg(
m_refreshRate, 0,
'f', 3).arg(Size.width()).arg(Size.height()));
790 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Using %1x%2@%3Hz for GUI")
797 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to change mode to %1x%2@%3Hz")
807 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Switched to %1x%2@%3Hz")
828 auto max = std::get<1>(range) > 60 ? std::get<1>(range) : 60;
841 auto targetrate =
static_cast<double>(NAN);
847 return modes[
static_cast<size_t>(match)].RefreshRates();
880 auto valid = [](
double Aspect) {
return (Aspect > 0.1 && Aspect < 10.0); };
886 Source = tr(
"Video mode override");
909 Source = tr(
"Multiscreen estimate");
920 if (valid(calculated))
922 if ((
override < 0.0) || !valid(detected))
924 Source = tr(
"Square pixels");
957 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Supported HDR formats: %1")
959 if (
auto brightness =
m_hdrState->GetMaxLuminance(); brightness > 1.0)
961 LOG(VB_GENERAL, LOG_NOTICE,
LOC + QString(
"Display reports max brightness of %1 nits")
962 .arg(
static_cast<int>(brightness)));
978 auto sortscreens = [](
const QScreen* First,
const QScreen* Second)
980 if (First->geometry().left() < Second->geometry().left())
982 if (First->geometry().top() < Second->geometry().top())
988 double result = 16.0 / 9.0;
990 QList<QScreen*> screens;
992 screens =
m_screen->virtualSiblings();
997 std::sort(screens.begin(), screens.end(), sortscreens);
998 QList<double> aspectratios;
999 QSize totalresolution;
1004 for (
auto it = screens.constBegin() ; it != screens.constEnd(); ++it)
1006 QRect geom = (*it)->geometry();
1007 totalresolution += geom.size();
1008 LOG(VB_PLAYBACK, LOG_DEBUG,
LOC + QString(
"%1x%2+%3+%4 %5")
1009 .arg(geom.width()).arg(geom.height()).arg(geom.left()).arg(geom.top())
1010 .arg((*it)->physicalSize().width() / (*it)->physicalSize().height()));
1011 if (lastleft < geom.left())
1014 lastleft = geom.left();
1016 if (lasttop < geom.top())
1019 lasttop = geom.top();
1022 aspectratios << (*it)->physicalSize().width() / (*it)->physicalSize().height();
1027 if (!totalresolution.isEmpty())
1028 result =
static_cast<double>(totalresolution.width()) / totalresolution.height();
1030 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Screen layout: %1x%2").arg(rows).arg(columns));
1031 if (rows == columns)
1033 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Grid layout");
1035 else if (rows == 1 && columns > 1)
1037 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Horizontal layout");
1039 else if (columns == 1 && rows > 1)
1041 LOG(VB_GENERAL, LOG_DEBUG,
LOC +
"Vertical layout");
1045 LOG(VB_GENERAL, LOG_INFO,
1046 LOC + QString(
"Unsupported layout - defaulting to %1 (%2/%3)")
1047 .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1052 double aspectratio = 0.0;
1053 double average = 0.0;
1055 for (
auto it2 = aspectratios.constBegin() ; it2 != aspectratios.constEnd(); ++it2, ++count)
1057 aspectratio += *it2;
1058 average = aspectratio / count;
1059 if (qAbs(*it2 - average) > 0.1)
1061 LOG(VB_GENERAL, LOG_INFO,
LOC +
1062 QString(
"Inconsistent aspect ratios - defaulting to %1 (%2/%3)")
1063 .arg(result).arg(totalresolution.width()).arg(totalresolution.height()));
1068 aspectratio = (average * columns) / rows;
1069 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Estimated aspect ratio: %1")
1091 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Waiting for resolution change");
1094 timer.setSingleShot(
true);
1095 connect(&timer, &
QTimer::timeout, [](){
LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Timed out wating for screen change"); });
1111 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Waiting for new screen");
1114 timer.setSingleShot(
true);
1115 connect(&timer, &
QTimer::timeout, [](){
LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Timed out waiting for new screen"); });
1126 if (pauselengthinms)
1128 LOG(VB_GENERAL, LOG_INFO,
LOC +
1129 QString(
"Pausing %1ms for video mode switch").arg(pauselengthinms));
1132 timer.setSingleShot(
true);
1135 timer.start(pauselengthinms);
1145 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"Available modes:");
1148 auto rates = (*it).RefreshRates();
1149 QStringList rateslist;
1150 for (
auto it2 = rates.crbegin(); it2 != rates.crend(); ++it2)
1151 rateslist.append(QString(
"%1").arg(*it2, 2,
'f', 2,
'0'));
1152 if (rateslist.empty())
1153 rateslist.append(
"Variable rate?");
1154 LOG(VB_PLAYBACK, LOG_INFO, QString(
"%1x%2\t%3")
1155 .arg((*it).Width()).arg((*it).Height()).arg(rateslist.join(
"\t")));
1167 auto forcevrr = CmdLine.
toBool(
"vrr");
1168 bool gsyncchanged =
false;
1169 bool freesyncchanged =
false;
1171#if CONFIG_QTWEBENGINE
1172 QApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
1173 QQuickWindow::setSceneGraphBackend(
"software");
1174 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Using shared OpenGL Contexts");
1178 QSurfaceFormat format;
1181 if (qEnvironmentVariableIsSet(
"MYTHTV_DEPTH"))
1184 int depth =
std::clamp(qEnvironmentVariableIntValue(
"MYTHTV_DEPTH"), 6, 16);
1185 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Trying to force depth to '%1'").arg(depth));
1186 format.setRedBufferSize(depth);
1190 format.setDepthBufferSize(0);
1191 format.setStencilBufferSize(0);
1193 format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
1194 format.setProfile(QSurfaceFormat::CompatibilityProfile);
1195 format.setSwapInterval(SwapInterval);
1196 QSurfaceFormat::setDefaultFormat(format);
1201 QApplication::setDesktopSettingsAware(
false);
1204#if CONFIG_DRM && CONFIG_QTPRIVATEHEADERS
1210#if CONFIG_WAYLANDEXTRAS
1215 MythDRMDevice::SetupDRM(CmdLine);
1221#if defined (Q_OS_LINUX) && CONFIG_EGL && CONFIG_X11
1233 QString soft = qgetenv(
"LIBGL_ALWAYS_SOFTWARE");
1234 bool ignore = soft ==
"1" || soft.compare(
"true", Qt::CaseInsensitive) == 0;
1235 bool allow = qEnvironmentVariableIsEmpty(
"MYTHTV_NO_EGL") && !ignore;
1236 bool force = !qEnvironmentVariableIsEmpty(
"MYTHTV_FORCE_EGL");
1241 if (vendor.contains(
"nvidia", Qt::CaseInsensitive) && !
force)
1243 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Not requesting EGL for vendor '%1'").arg(vendor));
1245 else if (!vendor.isEmpty() ||
force)
1247 LOG(VB_GENERAL, LOG_INFO,
LOC + QString(
"Requesting EGL for vendor '%1'").arg(vendor));
1248 setenv(
"QT_XCB_GL_INTEGRATION",
"xcb_egl", 0);
1253#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
1255 QApplication::setAttribute(Qt::AA_DisableHighDpiScaling);
1259 if (
auto display = CmdLine.
toString(
"display"); !display.isEmpty())
1270 if (forcevrr && !(gsyncchanged || freesyncchanged))
1271 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Variable refresh rate not adjusted");
Parent class for defining application command line parsers.
bool toBool(const QString &key) const
Returns stored QVariant as a boolean.
QString toString(const QString &key) const
Returns stored QVariant as a QString, falling to default if not provided.
uint toUInt(const QString &key) const
Returns stored QVariant as an unsigned integer, falling to default if not provided.
QString GetHostName(void)
QString GetSetting(const QString &key, const QString &defaultval="")
int GetNumSetting(const QString &key, int defaultval=0)
double GetFloatSettingOnHost(const QString &key, const QString &host, double defaultval=0.0)
static bool s_freeSyncResetOnExit
static bool CompareRates(double First, double Second, double Precision=0.01)
Determine whether two rates are considered equal with the given precision.
static int FindBestMatch(const MythDisplayModes &Modes, const MythDisplayMode &Mode, double &TargetRate)
void SetRefreshRate(double Rate)
double AspectRatio() const
double RefreshRate() const
static uint64_t FindBestScreen(const DisplayModeMap &Map, int Width, int Height, double Rate)
static uint64_t CalcKey(QSize Size, double Rate)
static bool IsAvailable()
double GetPixelAspectRatio()
virtual bool SwitchToVideoMode(QSize Size, double Framerate)
void InitScreenBounds()
Get screen size from Qt while respecting the user's multiscreen settings.
QStringList GetDescription()
static void PauseForModeSwitch()
double EstimateVirtualAspectRatio()
Estimate the overall display aspect ratio for multi screen setups.
double GetAspectRatio(QString &Source, bool IgnoreModeOverride=false)
Returns current screen aspect ratio.
void SwitchToDesktop()
Return the screen to the original desktop video mode.
virtual void UpdateCurrentMode()
Retrieve screen details.
static void GeometryChanged(QRect Geometry)
MythDisplayRates GetRefreshRates(QSize Size)
static void ConfigureQtGUI(int SwapInterval, const MythCommandLineParser &CmdLine)
Shared static initialisation code for all MythTV GUI applications.
MythDisplayMode m_guiMode
double GetRefreshRate() const
bool SwitchToVideo(QSize Size, double Rate=0.0)
Switches to the resolution and refresh rate defined in the database for the specified video resolutio...
void PhysicalDPIChanged(qreal DPI)
static QScreen * GetDesiredScreen()
static void DebugScreen(QScreen *qScreen, const QString &Message)
virtual bool VideoModesAvailable()
static MythDisplay * Create(MythMainWindow *MainWindow)
Create a MythDisplay object appropriate for the current platform.
bool SwitchToGUI(bool Wait=false)
Switches to the GUI resolution.
virtual void ScreenChanged(QScreen *qScreen)
The actual screen in use has changed. We must use it.
MythDisplayModes m_videoModes
bool m_waitForModeChanges
void ScreenRemoved(QScreen *qScreen)
MythDisplayMode m_desktopMode
QScreen * GetCurrentScreen()
Return a pointer to the screen to use.
static void PrimaryScreenChanged(QScreen *qScreen)
void ScreenCountChanged(int Screens)
void ScreenAdded(QScreen *qScreen)
DisplayModeMap m_overrideVideoModes
double m_aspectRatioOverride
void CurrentScreenChanged(QScreen *qScreen)
void WaitForScreenChange()
virtual const MythDisplayModes & GetVideoModes()
static QString GetExtraScreenInfo(QScreen *qScreen)
void SetWidget(QWidget *MainWindow)
Set the QWidget and QWindow in use.
std::chrono::microseconds GetRefreshInterval(std::chrono::microseconds Fallback) const
MythDisplayMode m_videoMode
bool NextModeIsLarger(QSize Size)
Check whether the next mode is larger in size than the current mode.
static bool SpanAllScreens()
Return true if the MythTV windows should span all screens.
static int GetScreenCount()
void CurrentDPIChanged(qreal DPI)
MythHDRDesc GetHDRSupport() const
static QString GetEGLVendor(void)
static bool s_gsyncResetOnExit
static void ForceGSync(bool Enable)
Enable or disable GSync before the main window is created.
static MythHDRPtr Create(class MythDisplay *MDisplay, const MythHDRDesc &Desc)
static QRect GetGeometryOverride()
static bool WindowIsAlwaysFullscreen()
Return true if the current platform only supports fullscreen windows.
static bool GeometryIsOverridden()
static MythVRRPtr Create(class MythDisplay *MDisplay)
Create a concrete implementation of MythVRR suitable for the given Display.
static void SetQtX11Display(const QString &DisplayStr)
static const struct wl_interface * types[]
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.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
std::vector< MythDisplayMode > MythDisplayModes
std::vector< double > MythDisplayRates
std::shared_ptr< class MythHDR > MythHDRPtr
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
static eu8 clamp(eu8 value, eu8 low, eu8 high)