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 typedef int (*XErrorCallbackType)(Display *, XErrorEvent *);
19 typedef std::vector<XErrorEvent> XErrorVectorType;
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 
60 {
61  MythXDisplay *disp = new MythXDisplay();
62  if (disp && disp->Open())
63  return disp;
64 
65  LOG(VB_GENERAL, LOG_CRIT, "MythXOpenDisplay() failed");
66  delete disp;
67  return nullptr;
68 }
69 
71 {
72  MythXLocker locker(this);
73  if (m_disp)
74  {
75  if (m_gc)
76  XFreeGC(m_disp, m_gc);
77  StopLog();
78  if (xdisplays.count(m_disp))
79  xdisplays.erase(m_disp);
80  XCloseDisplay(m_disp);
81  m_disp = nullptr;
82  }
83 }
84 
86 {
87  MythXLocker locker(this);
88 
89  QString dispStr = MythUIHelper::GetX11Display();
90  const char *dispCStr = nullptr;
91  if (!dispStr.isEmpty())
92  dispCStr = dispStr.toLatin1().constData();
93 
94  m_disp = XOpenDisplay(dispCStr);
95  if (!m_disp)
96  return false;
97 
98  xdisplays[m_disp] = this;
99  m_screen_num = DefaultScreen(m_disp);
100  m_screen = DefaultScreenOfDisplay(m_disp);
101  m_black = XBlackPixel(m_disp, m_screen_num);
102  m_depth = DefaultDepthOfScreen(m_screen);
103  m_root = DefaultRootWindow(m_disp);
104 
105  return true;
106 }
107 
108 bool MythXDisplay::CreateGC(Window win)
109 {
110  StartLog();
111  XLOCK(this, m_gc = XCreateGC(m_disp, win, 0, nullptr));
112  return StopLog();
113 }
114 
115 void MythXDisplay::SetForeground(unsigned long color)
116 {
117  if (!m_gc)
118  return;
119  XLOCK(this, XSetForeground(m_disp, m_gc, color));
120 }
121 
122 void MythXDisplay::FillRectangle(Window win, const QRect &rect)
123 {
124  if (!m_gc)
125  return;
126  XLOCK(this, XFillRectangle(m_disp, win, m_gc,
127  rect.left(), rect.top(),
128  rect.width(), rect.height()));
129 }
130 
131 void MythXDisplay::MoveResizeWin(Window win, const QRect &rect)
132 {
133  XLOCK(this, XMoveResizeWindow(m_disp, win,
134  rect.left(), rect.top(),
135  rect.width(), rect.height()));
136 }
137 
144 {
145  MythXLocker locker(this);
146  int displayWidthPixel = DisplayWidth( m_disp, m_screen_num);
147  int displayHeightPixel = DisplayHeight(m_disp, m_screen_num);
148  return {displayWidthPixel, displayHeightPixel};
149 }
150 
157 {
158  MythXLocker locker(this);
159  int displayWidthMM = DisplayWidthMM( m_disp, m_screen_num);
160  int displayHeightMM = DisplayHeightMM(m_disp, m_screen_num);
161  return {displayWidthMM, displayHeightMM};
162 }
163 
165 {
166  XF86VidModeModeLine mode_line;
167  int dot_clock;
168  MythXLocker locker(this);
169 
170  if (!XF86VidModeGetModeLine(m_disp, m_screen_num, &dot_clock, &mode_line))
171  {
172  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query failed");
173  return -1;
174  }
175 
176  double rate = mode_line.htotal * mode_line.vtotal;
177 
178  // Catch bad data from video drivers (divide by zero causes return of NaN)
179  if (rate == 0.0 || dot_clock == 0)
180  {
181  LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query returned zeroes");
182  return -1;
183  }
184 
185  rate = (dot_clock * 1000.0) / rate;
186 
187  if (((mode_line.flags & V_INTERLACE) != 0) &&
188  rate > 24.5 && rate < 30.5)
189  {
190  LOG(VB_PLAYBACK, LOG_INFO,
191  "Doubling refresh rate for interlaced display.");
192  rate *= 2.0;
193  }
194 
195  return rate;
196 }
197 
198 void MythXDisplay::Sync(bool flush)
199 {
200  XLOCK(this, XSync(m_disp, flush));
201 }
202 
204 {
205  if (!m_disp || xerror_handlers.count(m_disp))
206  return;
207 
208  Sync();
209  XLOCK(this, xerror_handlers[m_disp] = XSetErrorHandler(ErrorHandler));
210 }
211 
213 {
214  if (!(m_disp && xerror_handlers.count(m_disp)))
215  return false;
216 
217  Sync();
219  XLOCK(this, XSetErrorHandler(old_handler));
220  xerror_handlers.erase(m_disp);
221  return CheckErrors();
222 }
223 
224 bool MythXDisplay::CheckErrors(Display *disp)
225 {
226  if (!disp)
228 
229  Display *d = disp ? disp : m_disp;
230  if (!d)
231  return false;
232 
233  if (!xerrors.count(d))
234  return true;
235 
236  MythXLocker locker(this);
237  Sync();
238  const std::vector<XErrorEvent>& events = xerrors[d];
239 
240  if (events.empty())
241  return true;
242 
243  for (int i = events.size() -1; i>=0; --i)
244  {
245  char buf[200];
246  XGetErrorText(d, events[i].error_code, buf, sizeof(buf));
247  LOG(VB_GENERAL, LOG_ERR,
248  QString("\n"
249  "XError type: %1\n"
250  " serial no: %2\n"
251  " err code: %3 (%4)\n"
252  " req code: %5\n"
253  " minor code: %6\n"
254  "resource id: %7\n")
255  .arg(events[i].type)
256  .arg(events[i].serial)
257  .arg(events[i].error_code).arg(buf)
258  .arg(events[i].request_code)
259  .arg(events[i].minor_code)
260  .arg(events[i].resourceid));
261  }
262  xerrors.erase(d);
263  return false;
264 }
265 
267 {
268  if (xerrors.empty())
269  return;
270 
271  std::map<Display*, XErrorVectorType>::iterator errors = xerrors.begin();
272  for (; errors != xerrors.end(); ++errors)
273  if (!xerror_handlers.count(errors->first))
274  CheckErrors(errors->first);
275 }
276 
277 #endif // USING_X11
bool CheckErrors(Display *disp=nullptr)
bool CreateGC(Window win)
MythXDisplay * OpenMythXDisplay(void)
static QString GetX11Display(void)
#define XLOCK(dpy, arg)
Definition: mythxdisplay.h:75
unsigned long m_black
Definition: mythxdisplay.h:49
std::map< Display *, MythXDisplay * > xdisplays
This file is intended to hold X11 specific utility functions.
Definition: mythxdisplay.h:16
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:51
bool Open(void)
QSize GetDisplaySize(void)
Return the size of the X Display in pixels.
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
std::vector< XErrorEvent > XErrorVectorType
void SetForeground(unsigned long color)
Display * m_disp
Definition: mythxdisplay.h:45
Screen * m_screen
Definition: mythxdisplay.h:47
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
std::map< Display *, XErrorCallbackType > xerror_handlers
int(* XErrorCallbackType)(Display *, XErrorEvent *)
static int ErrorHandler(Display *d, XErrorEvent *xeev)
void CheckOrphanedErrors(void)
float GetRefreshRate(void)
void FillRectangle(Window win, const QRect &rect)
void LockMythXDisplays(bool lock)