MythTV  master
mythdisplay.cpp
Go to the documentation of this file.
1 #include "compat.h"
2 #include "mythcorecontext.h"
3 #include "mythdisplay.h"
4 #include "mythmainwindow.h"
5 
6 #include <QApplication>
7 
8 #if defined(Q_OS_MAC)
9 #import "util-osx.h"
10 #elif USING_X11
11 #include "mythxdisplay.h"
12 #endif
13 
14 #ifdef Q_OS_ANDROID
15 #include <QtAndroidExtras>
16 #endif
17 
18 #include <mythlogging.h>
19 #define LOC QString("DispInfo: ")
20 
21 #define VALID_RATE(rate) ((rate) > 20.0F && (rate) < 200.0F)
22 
23 static float fix_rate(int video_rate)
24 {
25  static const float default_rate = 1000000.0F / 60.0F;
26  float fixed = default_rate;
27  if (video_rate > 0)
28  {
29  fixed = static_cast<float>(video_rate) / 2.0F;
30  if (fixed < default_rate)
31  fixed = default_rate;
32  }
33  return fixed;
34 }
35 
37 {
38  WId win = 0;
39  QWidget *main_widget = (QWidget*)MythMainWindow::getMainWindow();
40  if (main_widget)
41  win = main_widget->winId();
42  return win;
43 }
44 
46 {
47  DisplayInfo ret;
48 
49 #if defined(Q_OS_MAC)
50  CGDirectDisplayID disp = GetOSXDisplay(GetWindowID());
51  if (!disp)
52  return ret;
53 
54  CFDictionaryRef ref = CGDisplayCurrentMode(disp);
55  float rate = 0.0F;
56  if (ref)
57  rate = get_float_CF(ref, kCGDisplayRefreshRate);
58 
59  if (VALID_RATE(rate))
60  ret.m_rate = 1000000.0F / rate;
61  else
62  ret.m_rate = fix_rate(video_rate);
63 
64  CGSize size_in_mm = CGDisplayScreenSize(disp);
65  ret.m_size = QSize((uint) size_in_mm.width, (uint) size_in_mm.height);
66 
67  uint width = (uint)CGDisplayPixelsWide(disp);
68  uint height = (uint)CGDisplayPixelsHigh(disp);
69  ret.m_res = QSize(width, height);
70 
71 #elif defined(Q_OS_WIN)
72  HDC hdc = GetDC((HWND)GetWindowID());
73  int rate = 0;
74  if (hdc)
75  {
76  rate = GetDeviceCaps(hdc, VREFRESH);
77  int width = GetDeviceCaps(hdc, HORZSIZE);
78  int height = GetDeviceCaps(hdc, VERTSIZE);
79  ret.m_size = QSize((uint)width, (uint)height);
80  width = GetDeviceCaps(hdc, HORZRES);
81  height = GetDeviceCaps(hdc, VERTRES);
82  ret.m_res = QSize((uint)width, (uint)height);
83  }
84 
85  if (VALID_RATE(rate))
86  {
87  // see http://support.microsoft.com/kb/2006076
88  switch (rate)
89  {
90  case 23: ret.m_rate = 41708; break; // 23.976Hz
91  case 29: ret.m_rate = 33367; break; // 29.970Hz
92  case 47: ret.m_rate = 20854; break; // 47.952Hz
93  case 59: ret.m_rate = 16683; break; // 59.940Hz
94  case 71: ret.m_rate = 13903; break; // 71.928Hz
95  case 119: ret.m_rate = 8342; break; // 119.880Hz
96  default: ret.m_rate = 1000000.0F / (float)rate;
97  }
98  }
99  else
100  ret.m_rate = fix_rate(video_rate);
101 
102 #elif USING_X11
103  MythXDisplay *disp = OpenMythXDisplay();
104  if (!disp)
105  return ret;
106 
107  float rate = disp->GetRefreshRate();
108  if (VALID_RATE(rate))
109  ret.m_rate = 1000000.0F / rate;
110  else
111  ret.m_rate = fix_rate(video_rate);
112  ret.m_res = disp->GetDisplaySize();
113  ret.m_size = disp->GetDisplayDimensions();
114  delete disp;
115 #elif defined(Q_OS_ANDROID)
116  QAndroidJniEnvironment env;
117  QAndroidJniObject activity = QtAndroid::androidActivity();
118  QAndroidJniObject windowManager = activity.callObjectMethod("getWindowManager", "()Landroid/view/WindowManager;");
119  QAndroidJniObject display = windowManager.callObjectMethod("getDefaultDisplay", "()Landroid/view/Display;");
120  QAndroidJniObject displayMetrics("android/util/DisplayMetrics");
121  display.callMethod<void>("getRealMetrics", "(Landroid/util/DisplayMetrics;)V", displayMetrics.object());
122  // check if passed or try a different method
123  if (env->ExceptionCheck())
124  {
125  env->ExceptionClear();
126  display.callMethod<void>("getMetrics", "(Landroid/util/DisplayMetrics;)V", displayMetrics.object());
127  }
128  float xdpi = displayMetrics.getField<jfloat>("xdpi");
129  float ydpi = displayMetrics.getField<jfloat>("ydpi");
130  int height = displayMetrics.getField<jint>("heightPixels");
131  int width = displayMetrics.getField<jint>("widthPixels");
132  float rate = display.callMethod<jfloat>("getRefreshRate");
133  LOG(VB_GENERAL, LOG_INFO, LOC +
134  QString("rate:%1 h:%2 w:%3 xdpi:%4 ydpi:%5")
135  .arg(rate).arg(height).arg(width)
136  .arg(xdpi).arg(ydpi)
137  );
138 
139  if (VALID_RATE(rate))
140  ret.m_rate = 1000000.0F / rate;
141  else
142  ret.m_rate = fix_rate(video_rate);
143  ret.m_res = QSize((uint)width, (uint)height);
144  ret.m_size = QSize((uint)width, (uint)height);
145  if (xdpi > 0 && ydpi > 0)
146  ret.m_size = QSize((uint)width/xdpi*25.4F, (uint)height/ydpi*25.4F);
147 #endif
148  return ret;
149 }
150 
160 {
161  return qGuiApp->screens().size();
162 }
163 
168 {
169  return gCoreContext->GetSetting("XineramaScreen", nullptr) == "-1";
170 }
171 
186 {
187  // Lookup by name
188  QString name = gCoreContext->GetSetting("XineramaScreen", nullptr);
189  foreach (QScreen *qscreen, qGuiApp->screens()) {
190  if (name == qscreen->name()) {
191  LOG(VB_GUI, LOG_INFO, LOC +
192  QString("found screen %1").arg(name));
193  return qscreen;
194  }
195  }
196 
197  // No name match. These were previously numbers.
198  bool ok;
199  int screen_num = name.toInt(&ok);
200  QList<QScreen *>screens = qGuiApp->screens();
201  if (ok && (screen_num >= 0) && (screen_num < screens.size())) {
202  LOG(VB_GUI, LOG_INFO, LOC +
203  QString("found screen number %1 (%2)")
204  .arg(name).arg(screens[screen_num]->name()));
205  return screens[screen_num];
206  }
207 
208  // For aything else, return the primary screen.
209  QScreen *primary = qGuiApp->primaryScreen();
210  if (name != "-1")
211  LOG(VB_GUI, LOG_INFO,
212  QString("screen %1 not found, defaulting to primary screen (%2)")
213  .arg(name).arg(primary->name()));
214  return primary;
215 }
216 
217 QString MythDisplay::GetExtraScreenInfo(QScreen *qscreen)
218 {
219 #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0)
220  QString mfg = qscreen->manufacturer();
221  if (mfg.isEmpty())
222  mfg = "unknown";
223  QString model = qscreen->model();
224  if (model.isEmpty())
225  model = "unknown";
226  return QString("(%1 %2)").arg(mfg).arg(model);
227 #else
228  Q_UNUSED(qscreen);
229  return QString();
230 #endif
231 }
MythXDisplay * OpenMythXDisplay(void)
static WId GetWindowID(void)
Definition: mythdisplay.cpp:36
float get_float_CF(CFDictionaryRef dict, CFStringRef key)
Definition: util-osx.cpp:36
static QString GetExtraScreenInfo(QScreen *qscreen)
static MythMainWindow * getMainWindow(const bool useDB=true)
Return the existing main window, or create one.
This file is intended to hold X11 specific utility functions.
Definition: mythxdisplay.h:16
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
CGDirectDisplayID GetOSXDisplay(WId win)
Definition: util-osx.cpp:50
static QScreen * GetScreen(void)
Return a pointer to the screen to use.
#define LOC
Definition: mythdisplay.cpp:19
float m_rate
Definition: mythdisplay.h:21
#define VALID_RATE(rate)
Definition: mythdisplay.cpp:21
QSize GetDisplayDimensions(void)
Return the size of the X Display in millimeters.
QSize m_res
Definition: mythdisplay.h:20
QSize GetDisplaySize(void)
Return the size of the X Display in pixels.
QString GetSetting(const QString &key, const QString &defaultval="")
const char * name
Definition: ParseText.cpp:328
static float fix_rate(int video_rate)
Definition: mythdisplay.cpp:23
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QSize m_size
Definition: mythdisplay.h:19
static DisplayInfo GetDisplayInfo(int video_rate=0)
Definition: mythdisplay.cpp:45
float GetRefreshRate(void)
static bool SpanAllScreens(void)
Return true if the MythTV windows should span all screens.
static int GetNumberOfScreens(void)
Return the number of available screens.