MythTV  master
mythxdisplay.cpp
Go to the documentation of this file.
1 // Std
2 #include <map>
3 #include <vector>
4 
5 // MythTV
6 #include "config.h" // for CONFIG_DARWIN
7 #include "mythlogging.h"
8 #include "mythuihelper.h"
9 
10 #ifdef USING_X11
11 #include "mythxdisplay.h"
12 #ifndef V_INTERLACE
13 #define V_INTERLACE (0x010)
14 #endif
15 extern "C" {
16 #include <X11/extensions/Xinerama.h>
17 #include <X11/extensions/xf86vmode.h>
18 }
19 using XErrorCallbackType = int (*)(Display *, XErrorEvent *);
20 using XErrorVectorType = std::vector<XErrorEvent>;
21 static std::map<Display*, XErrorVectorType> xerrors;
22 static std::map<Display*, XErrorCallbackType> xerror_handlers;
23 
24 static int ErrorHandler(Display *d, XErrorEvent *xeev)
25 {
26  xerrors[d].push_back(*xeev);
27  return 0;
28 }
29 
31 {
32  public:
33  explicit MythXLocker(MythXDisplay* Disp)
34  : m_disp(Disp)
35  {
36  if (m_disp)
37  m_disp->Lock();
38  }
39 
41  {
42  if (m_disp)
43  m_disp->Unlock();
44  }
45 
46  private:
47  MythXDisplay *m_disp { nullptr };
48 };
49 
51 {
52  auto *disp = new MythXDisplay();
53  if (disp && disp->Open())
54  return disp;
55 
56  if (Warn)
57  LOG(VB_GENERAL, LOG_CRIT, "MythXOpenDisplay() failed");
58  delete disp;
59  return nullptr;
60 }
61 
63 {
64  MythXLocker locker(this);
65  if (m_disp)
66  {
67  StopLog();
68  XCloseDisplay(m_disp);
69  m_disp = nullptr;
70  }
71 }
72 
74 {
75  MythXLocker locker(this);
76 
78  const char *dispCStr = nullptr;
79  if (!m_displayName.isEmpty())
80  dispCStr = m_displayName.toLatin1().constData();
81 
82  m_disp = XOpenDisplay(dispCStr);
83  if (!m_disp)
84  return false;
85 
86  m_screenNum = DefaultScreen(m_disp);
87  m_screen = DefaultScreenOfDisplay(m_disp);
88  m_depth = DefaultDepthOfScreen(m_screen);
89  m_root = DefaultRootWindow(m_disp);
90 
91  return true;
92 }
93 
100 {
101  XF86VidModeModeLine mode;
102  int dummy = 0;
103  MythXLocker locker(this);
104 
105  if (!XF86VidModeGetModeLine(m_disp, m_screenNum, &dummy, &mode))
106  {
107  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query failed");
108  // Fallback to old display size code - which is not updated for mode switches
109  return {DisplayWidth(m_disp, m_screenNum),
110  DisplayHeight(m_disp, m_screenNum)};
111  }
112 
113  return { mode.hdisplay, mode.vdisplay };
114 }
115 
122 {
123  MythXLocker locker(this);
124  int displayWidthMM = DisplayWidthMM( m_disp, m_screenNum);
125  int displayHeightMM = DisplayHeightMM(m_disp, m_screenNum);
126  return { displayWidthMM, displayHeightMM };
127 }
128 
130 {
131  XF86VidModeModeLine mode_line;
132  int dot_clock = 0;
133  MythXLocker locker(this);
134 
135  if (!XF86VidModeGetModeLine(m_disp, m_screenNum, &dot_clock, &mode_line))
136  {
137  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query failed");
138  return -1;
139  }
140 
141  double rate = mode_line.htotal * mode_line.vtotal;
142 
143  // Catch bad data from video drivers (divide by zero causes return of NaN)
144  if (rate == 0.0 || dot_clock == 0)
145  {
146  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query returned zeroes");
147  return -1;
148  }
149 
150  rate = (dot_clock * 1000.0) / rate;
151 
152  if (((mode_line.flags & V_INTERLACE) != 0) && rate > 24.5 && rate < 30.5)
153  {
154  LOG(VB_PLAYBACK, LOG_INFO,
155  "Doubling refresh rate for interlaced display.");
156  rate *= 2.0;
157  }
158 
159  return rate;
160 }
161 
162 void MythXDisplay::Sync(bool Flush)
163 {
164  XLOCK(this, XSync(m_disp, Flush));
165 }
166 
168 {
169  if (!m_disp || xerror_handlers.count(m_disp))
170  return;
171 
172  Sync();
173  XLOCK(this, xerror_handlers[m_disp] = XSetErrorHandler(ErrorHandler));
174 }
175 
177 {
178  if (!(m_disp && xerror_handlers.count(m_disp)))
179  return false;
180 
181  Sync();
183  XLOCK(this, XSetErrorHandler(old_handler));
184  xerror_handlers.erase(m_disp);
185  return CheckErrors();
186 }
187 
188 bool MythXDisplay::CheckErrors(Display *Disp)
189 {
190  if (!Disp)
192 
193  Display *d = Disp ? Disp : m_disp;
194  if (!d)
195  return false;
196 
197  if (!xerrors.count(d))
198  return true;
199 
200  MythXLocker locker(this);
201  Sync();
202  const std::vector<XErrorEvent>& events = xerrors[d];
203 
204  if (events.empty())
205  return true;
206 
207  for (const auto & event : events)
208  {
209  char buf[200];
210  XGetErrorText(d, event.error_code, buf, sizeof(buf));
211  LOG(VB_GENERAL, LOG_ERR,
212  QString("XError type: %1\nSerial no: %2\nErr code: %3 (%4)\n"
213  "Req code: %5\nmMinor code: %6\nResource id: %7\n")
214  .arg(event.type).arg(event.serial)
215  .arg(event.error_code).arg(buf)
216  .arg(event.request_code).arg(event.minor_code)
217  .arg(event.resourceid));
218  }
219  xerrors.erase(d);
220  return false;
221 }
222 
224 {
225  if (xerrors.empty())
226  return;
227 
228  for (auto & xerror : xerrors)
229  if (!xerror_handlers.count(xerror.first))
230  CheckErrors(xerror.first);
231 }
232 
233 #endif // USING_X11
double GetRefreshRate(void)
void Unlock(void)
Definition: mythxdisplay.h:32
static QString GetX11Display(void)
MythXDisplay * m_disp
#define XLOCK(dpy, arg)
Definition: mythxdisplay.h:19
bool CheckErrors(Display *Disp=nullptr)
void Lock(void)
Definition: mythxdisplay.h:31
static MythXDisplay * OpenMythXDisplay(bool Warn=true)
bool StopLog(void)
QSize GetDisplayDimensions(void)
Return the size of the X Display in millimeters.
Window m_root
Definition: mythxdisplay.h:51
std::vector< XErrorEvent > XErrorVectorType
bool Open(void)
QSize GetDisplaySize(void)
Return the size of the X Display in pixels.
int(*)(Display *, XErrorEvent *) XErrorCallbackType
QString m_displayName
Definition: mythxdisplay.h:53
void Sync(bool Flush=false)
static const uint16_t * d
void StartLog(void)
#define V_INTERLACE
static std::map< Display *, XErrorVectorType > xerrors
Display * m_disp
Definition: mythxdisplay.h:47
Screen * m_screen
Definition: mythxdisplay.h:49
static std::map< Display *, XErrorCallbackType > xerror_handlers
static int ErrorHandler(Display *d, XErrorEvent *xeev)
void CheckOrphanedErrors(void)
MythXLocker(MythXDisplay *Disp)
MythXDisplay()=default
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23