MythTV  master
mythxdisplay.cpp
Go to the documentation of this file.
1 
2 #include <map>
3 #include <vector>
4 
5 #include "config.h" // for CONFIG_DARWIN
6 #include "mythlogging.h"
7 #include "mythuihelper.h"
8 
9 #ifdef USING_X11
10 #include "mythxdisplay.h"
11 #ifndef V_INTERLACE
12 #define V_INTERLACE (0x010)
13 #endif
14 extern "C" {
15 #include <X11/extensions/Xinerama.h>
16 #include <X11/extensions/xf86vmode.h>
17 }
18 using XErrorCallbackType = int (*)(Display *, XErrorEvent *);
19 using XErrorVectorType = std::vector<XErrorEvent>;
20 std::map<Display*, XErrorVectorType> xerrors;
21 std::map<Display*, XErrorCallbackType> xerror_handlers;
22 std::map<Display*, MythXDisplay*> xdisplays;
23 #endif // USING_X11
24 
25 #include <QMutex>
26 
27 // Everything below this line is only compiled if using X11
28 #ifdef USING_X11
29 
30 static int ErrorHandler(Display *d, XErrorEvent *xeev)
31 {
32  xerrors[d].push_back(*xeev);
33  return 0;
34 }
35 
36 void LockMythXDisplays(bool lock)
37 {
38  if (lock)
39  {
40  std::map<Display*, MythXDisplay*>::iterator it;
41  for (it = xdisplays.begin(); it != xdisplays.end(); ++it)
42  it->second->Lock();
43  }
44  else
45  {
46  std::map<Display*, MythXDisplay*>::reverse_iterator it;
47  for (it = xdisplays.rbegin(); it != xdisplays.rend(); ++it)
48  it->second->Unlock();
49  }
50 }
51 
53 {
54  if (xdisplays.count(d))
55  return xdisplays[d];
56  return nullptr;
57 }
58 
59 MythXDisplay *OpenMythXDisplay(bool Warn /*= true*/)
60 {
61  auto *disp = new MythXDisplay();
62  if (disp && disp->Open())
63  return disp;
64 
65  if (Warn)
66  LOG(VB_GENERAL, LOG_CRIT, "MythXOpenDisplay() failed");
67  delete disp;
68  return nullptr;
69 }
70 
72 {
73  MythXLocker locker(this);
74  if (m_disp)
75  {
76  if (m_gc)
77  XFreeGC(m_disp, m_gc);
78  StopLog();
79  if (xdisplays.count(m_disp))
80  xdisplays.erase(m_disp);
81  XCloseDisplay(m_disp);
82  m_disp = nullptr;
83  }
84 }
85 
87 {
88  MythXLocker locker(this);
89 
91  const char *dispCStr = nullptr;
92  if (!m_displayName.isEmpty())
93  dispCStr = m_displayName.toLatin1().constData();
94 
95  m_disp = XOpenDisplay(dispCStr);
96  if (!m_disp)
97  return false;
98 
99  xdisplays[m_disp] = this;
100  m_screenNum = DefaultScreen(m_disp);
101  m_screen = DefaultScreenOfDisplay(m_disp);
102  m_black = XBlackPixel(m_disp, m_screenNum);
103  m_depth = DefaultDepthOfScreen(m_screen);
104  m_root = DefaultRootWindow(m_disp);
105 
106  return true;
107 }
108 
109 bool MythXDisplay::CreateGC(Window win)
110 {
111  StartLog();
112  XLOCK(this, m_gc = XCreateGC(m_disp, win, 0, nullptr));
113  return StopLog();
114 }
115 
116 void MythXDisplay::SetForeground(unsigned long color)
117 {
118  if (!m_gc)
119  return;
120  XLOCK(this, XSetForeground(m_disp, m_gc, color));
121 }
122 
123 void MythXDisplay::FillRectangle(Window win, const QRect &rect)
124 {
125  if (!m_gc)
126  return;
127  XLOCK(this, XFillRectangle(m_disp, win, m_gc,
128  rect.left(), rect.top(),
129  rect.width(), rect.height()));
130 }
131 
132 void MythXDisplay::MoveResizeWin(Window win, const QRect &rect)
133 {
134  XLOCK(this, XMoveResizeWindow(m_disp, win,
135  rect.left(), rect.top(),
136  rect.width(), rect.height()));
137 }
138 
145 {
146  MythXLocker locker(this);
147  int displayWidthPixel = DisplayWidth( m_disp, m_screenNum);
148  int displayHeightPixel = DisplayHeight(m_disp, m_screenNum);
149  return {displayWidthPixel, displayHeightPixel};
150 }
151 
158 {
159  MythXLocker locker(this);
160  int displayWidthMM = DisplayWidthMM( m_disp, m_screenNum);
161  int displayHeightMM = DisplayHeightMM(m_disp, m_screenNum);
162  return {displayWidthMM, displayHeightMM};
163 }
164 
166 {
167  XF86VidModeModeLine mode_line;
168  int dot_clock = 0;
169  MythXLocker locker(this);
170 
171  if (!XF86VidModeGetModeLine(m_disp, m_screenNum, &dot_clock, &mode_line))
172  {
173  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query failed");
174  return -1;
175  }
176 
177  double rate = mode_line.htotal * mode_line.vtotal;
178 
179  // Catch bad data from video drivers (divide by zero causes return of NaN)
180  if (rate == 0.0 || dot_clock == 0)
181  {
182  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query returned zeroes");
183  return -1;
184  }
185 
186  rate = (dot_clock * 1000.0) / rate;
187 
188  if (((mode_line.flags & V_INTERLACE) != 0) &&
189  rate > 24.5 && rate < 30.5)
190  {
191  LOG(VB_PLAYBACK, LOG_INFO,
192  "Doubling refresh rate for interlaced display.");
193  rate *= 2.0;
194  }
195 
196  return rate;
197 }
198 
199 void MythXDisplay::Sync(bool flush)
200 {
201  XLOCK(this, XSync(m_disp, flush));
202 }
203 
205 {
206  if (!m_disp || xerror_handlers.count(m_disp))
207  return;
208 
209  Sync();
210  XLOCK(this, xerror_handlers[m_disp] = XSetErrorHandler(ErrorHandler));
211 }
212 
214 {
215  if (!(m_disp && xerror_handlers.count(m_disp)))
216  return false;
217 
218  Sync();
220  XLOCK(this, XSetErrorHandler(old_handler));
221  xerror_handlers.erase(m_disp);
222  return CheckErrors();
223 }
224 
225 bool MythXDisplay::CheckErrors(Display *disp)
226 {
227  if (!disp)
229 
230  Display *d = disp ? disp : m_disp;
231  if (!d)
232  return false;
233 
234  if (!xerrors.count(d))
235  return true;
236 
237  MythXLocker locker(this);
238  Sync();
239  const std::vector<XErrorEvent>& events = xerrors[d];
240 
241  if (events.empty())
242  return true;
243 
244  for (int i = events.size() -1; i>=0; --i)
245  {
246  char buf[200];
247  XGetErrorText(d, events[i].error_code, buf, sizeof(buf));
248  LOG(VB_GENERAL, LOG_ERR,
249  QString("\n"
250  "XError type: %1\n"
251  " serial no: %2\n"
252  " err code: %3 (%4)\n"
253  " req code: %5\n"
254  " minor code: %6\n"
255  "resource id: %7\n")
256  .arg(events[i].type)
257  .arg(events[i].serial)
258  .arg(events[i].error_code).arg(buf)
259  .arg(events[i].request_code)
260  .arg(events[i].minor_code)
261  .arg(events[i].resourceid));
262  }
263  xerrors.erase(d);
264  return false;
265 }
266 
268 {
269  if (xerrors.empty())
270  return;
271 
272  auto errors = xerrors.begin();
273  for (; errors != xerrors.end(); ++errors)
274  if (!xerror_handlers.count(errors->first))
275  CheckErrors(errors->first);
276 }
277 
278 #endif // USING_X11
bool CheckErrors(Display *disp=nullptr)
bool CreateGC(Window win)
MythXDisplay * OpenMythXDisplay(bool Warn)
static QString GetX11Display(void)
#define XLOCK(dpy, arg)
Definition: mythxdisplay.h:78
unsigned long m_black
Definition: mythxdisplay.h:51
std::map< Display *, MythXDisplay * > xdisplays
This file is intended to hold X11 specific utility functions.
Definition: mythxdisplay.h:17
bool StopLog(void)
void Sync(bool flush=false)
QSize GetDisplayDimensions(void)
Return the size of the X Display in millimeters.
Window m_root
Definition: mythxdisplay.h:53
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:55
void MoveResizeWin(Window win, const QRect &rect)
static const uint16_t * d
MythXDisplay * GetMythXDisplay(Display *d)
void StartLog(void)
#define V_INTERLACE
This file is intended to hold X11 specific utility functions.
std::map< Display *, XErrorVectorType > xerrors
void SetForeground(unsigned long color)
Display * m_disp
Definition: mythxdisplay.h:47
Screen * m_screen
Definition: mythxdisplay.h:49
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
std::map< Display *, XErrorCallbackType > xerror_handlers
static int ErrorHandler(Display *d, XErrorEvent *xeev)
void CheckOrphanedErrors(void)
float GetRefreshRate(void)
void FillRectangle(Window win, const QRect &rect)
void LockMythXDisplays(bool lock)