MythTV  0.26-pre
mythxdisplay.cpp
Go to the documentation of this file.
00001 
00002 #include <map>
00003 #include <vector>
00004 
00005 #include "config.h" // for CONFIG_DARWIN
00006 #include "mythlogging.h"
00007 #include "mythuihelper.h"
00008 
00009 #ifdef USING_X11
00010 #include "mythxdisplay.h"
00011 #ifndef V_INTERLACE
00012 #define V_INTERLACE (0x010)
00013 #endif
00014 extern "C" {
00015 #include <X11/extensions/Xinerama.h>
00016 #include <X11/extensions/xf86vmode.h>
00017 }
00018 typedef int (*XErrorCallbackType)(Display *, XErrorEvent *);
00019 typedef std::vector<XErrorEvent>       XErrorVectorType;
00020 std::map<Display*, XErrorVectorType>   xerrors;
00021 std::map<Display*, XErrorCallbackType> xerror_handlers;
00022 std::map<Display*, MythXDisplay*>      xdisplays;
00023 #endif // USING_X11
00024 
00025 #include <QMutex>
00026 
00027 // Everything below this line is only compiled if using X11
00028 #ifdef USING_X11
00029 
00030 static int ErrorHandler(Display *d, XErrorEvent *xeev)
00031 {
00032     xerrors[d].push_back(*xeev);
00033     return 0;
00034 }
00035 
00036 void LockMythXDisplays(bool lock)
00037 {
00038     if (lock)
00039     {
00040         std::map<Display*, MythXDisplay*>::iterator it;
00041         for (it = xdisplays.begin(); it != xdisplays.end(); ++it)
00042             it->second->Lock();
00043     }
00044     else
00045     {
00046         std::map<Display*, MythXDisplay*>::reverse_iterator it;
00047         for (it = xdisplays.rbegin(); it != xdisplays.rend(); ++it)
00048             it->second->Unlock();
00049     }
00050 }
00051 
00052 MythXDisplay *GetMythXDisplay(Display *d)
00053 {
00054     if (xdisplays.count(d))
00055         return xdisplays[d];
00056     return NULL;
00057 }
00058 
00059 MythXDisplay *OpenMythXDisplay(void)
00060 {
00061     MythXDisplay *disp = new MythXDisplay();
00062     if (disp && disp->Open())
00063         return disp;
00064 
00065     LOG(VB_GENERAL, LOG_CRIT, "MythXOpenDisplay() failed");
00066     delete disp;
00067     return NULL;
00068 }
00069 
00070 MythXDisplay::MythXDisplay()
00071   : m_disp(NULL), m_screen_num(0), m_screen(NULL),
00072     m_depth(0), m_black(0), m_gc(0),
00073     m_root(0), m_lock(QMutex::Recursive)
00074 {
00075 }
00076 
00077 MythXDisplay::~MythXDisplay()
00078 {
00079     MythXLocker locker(this);
00080     if (m_disp)
00081     {
00082         if (m_gc)
00083             XFreeGC(m_disp, m_gc);
00084         StopLog();
00085         if (xdisplays.count(m_disp))
00086             xdisplays.erase(m_disp);
00087         XCloseDisplay(m_disp);
00088         m_disp = NULL;
00089     }
00090 }
00091 
00092 bool MythXDisplay::Open(void)
00093 {
00094     MythXLocker locker(this);
00095 
00096     QString dispStr = GetMythUI()->GetX11Display();
00097     const char *dispCStr = NULL;
00098     if (!dispStr.isEmpty())
00099         dispCStr = dispStr.toAscii().constData();
00100 
00101     m_disp = XOpenDisplay(dispCStr);
00102     if (!m_disp)
00103         return false;
00104 
00105     xdisplays[m_disp] = this;
00106     m_screen_num = DefaultScreen(m_disp);
00107     m_screen     = DefaultScreenOfDisplay(m_disp);
00108     m_black      = XBlackPixel(m_disp, m_screen_num);
00109     m_depth      = DefaultDepthOfScreen(m_screen);
00110     m_root       = DefaultRootWindow(m_disp);
00111 
00112     return true;
00113 }
00114 
00115 bool MythXDisplay::CreateGC(Window win)
00116 {
00117     StartLog();
00118     XLOCK(this, m_gc = XCreateGC(m_disp, win, 0, NULL));
00119     return StopLog();
00120 }
00121 
00122 void MythXDisplay::SetForeground(unsigned long color)
00123 {
00124     if (!m_gc)
00125         return;
00126     XLOCK(this, XSetForeground(m_disp, m_gc, color));
00127 }
00128 
00129 void MythXDisplay::FillRectangle(Window win, const QRect &rect)
00130 {
00131     if (!m_gc)
00132         return;
00133     XLOCK(this, XFillRectangle(m_disp, win, m_gc,
00134                               rect.left(), rect.top(),
00135                               rect.width(), rect.height()));
00136 }
00137 
00138 void MythXDisplay::MoveResizeWin(Window win, const QRect &rect)
00139 {
00140     XLOCK(this, XMoveResizeWindow(m_disp, win,
00141                                  rect.left(), rect.top(),
00142                                  rect.width(), rect.height()));
00143 }
00144 
00145 int MythXDisplay::GetNumberXineramaScreens(void)
00146 {
00147     MythXLocker locker(this);
00148     int nr_xinerama_screens = 0;
00149     int event_base = 0, error_base = 0;
00150     if (XineramaQueryExtension(m_disp, &event_base, &error_base) &&
00151         XineramaIsActive(m_disp))
00152     {
00153         XFree(XineramaQueryScreens(m_disp, &nr_xinerama_screens));
00154     }
00155     return nr_xinerama_screens;
00156 }
00157 
00158 QSize MythXDisplay::GetDisplaySize(void)
00159 {
00160     MythXLocker locker(this);
00161     int displayWidthPixel  = DisplayWidth( m_disp, m_screen_num);
00162     int displayHeightPixel = DisplayHeight(m_disp, m_screen_num);
00163     return QSize(displayWidthPixel, displayHeightPixel);
00164 }
00165 
00166 QSize MythXDisplay::GetDisplayDimensions(void)
00167 {
00168     MythXLocker locker(this);
00169     int displayWidthMM  = DisplayWidthMM( m_disp, m_screen_num);
00170     int displayHeightMM = DisplayHeightMM(m_disp, m_screen_num);
00171     return QSize(displayWidthMM, displayHeightMM);
00172 }
00173 
00174 float MythXDisplay::GetRefreshRate(void)
00175 {
00176     XF86VidModeModeLine mode_line;
00177     int dot_clock;
00178     MythXLocker locker(this);
00179 
00180     if (!XF86VidModeGetModeLine(m_disp, m_screen_num, &dot_clock, &mode_line))
00181     {
00182         LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query failed");
00183         return -1;
00184     }
00185 
00186     double rate = mode_line.htotal * mode_line.vtotal;
00187 
00188     // Catch bad data from video drivers (divide by zero causes return of NaN)
00189     if (rate == 0.0 || dot_clock == 0)
00190     {
00191         LOG(VB_GENERAL, LOG_ERR, "X11 ModeLine query returned zeroes");
00192         return -1;
00193     }
00194 
00195     rate = (dot_clock * 1000.0) / rate;
00196 
00197     if (((mode_line.flags & V_INTERLACE) != 0) &&
00198         rate > 24.5 && rate < 30.5)
00199     {
00200         LOG(VB_PLAYBACK, LOG_INFO,
00201                 "Doubling refresh rate for interlaced display.");
00202         rate *= 2.0;
00203     }
00204 
00205     return rate;
00206 }
00207 
00208 void MythXDisplay::Sync(bool flush)
00209 {
00210     XLOCK(this, XSync(m_disp, flush));
00211 }
00212 
00213 void MythXDisplay::StartLog(void)
00214 {
00215     if (!m_disp || xerror_handlers.count(m_disp))
00216         return;
00217 
00218     Sync();
00219     XLOCK(this, xerror_handlers[m_disp] = XSetErrorHandler(ErrorHandler));
00220 }
00221 
00222 bool MythXDisplay::StopLog(void)
00223 {
00224     if (!(m_disp && xerror_handlers.count(m_disp)))
00225         return false;
00226 
00227     Sync();
00228     XErrorCallbackType old_handler = xerror_handlers[m_disp];
00229     XLOCK(this, XSetErrorHandler(old_handler));
00230     xerror_handlers.erase(m_disp);
00231     return CheckErrors();
00232 }
00233 
00234 bool MythXDisplay::CheckErrors(Display *disp)
00235 {
00236     if (!disp)
00237         CheckOrphanedErrors();
00238 
00239     Display *d = disp ? disp : m_disp;
00240     if (!d)
00241         return false;
00242 
00243     if (!xerrors.count(d))
00244         return true;
00245 
00246     MythXLocker locker(this);
00247     Sync();
00248     const std::vector<XErrorEvent>& events = xerrors[d];
00249 
00250     if (events.size() < 1)
00251         return true;
00252 
00253     for (int i = events.size() -1; i>=0; --i)
00254     {
00255         char buf[200];
00256         XGetErrorText(d, events[i].error_code, buf, sizeof(buf));
00257         LOG(VB_GENERAL, LOG_ERR,
00258             QString("\n"
00259                    "XError type: %1\n"
00260                    "  serial no: %2\n"
00261                    "   err code: %3 (%4)\n"
00262                    "   req code: %5\n"
00263                    " minor code: %6\n"
00264                    "resource id: %7\n")
00265                    .arg(events[i].type)
00266                    .arg(events[i].serial)
00267                    .arg(events[i].error_code).arg(buf)
00268                    .arg(events[i].request_code)
00269                    .arg(events[i].minor_code)
00270                    .arg(events[i].resourceid));
00271     }
00272     xerrors.erase(d);
00273     return false;
00274 }
00275 
00276 void MythXDisplay::CheckOrphanedErrors(void)
00277 {
00278     if (xerrors.size() < 1)
00279         return;
00280 
00281     std::map<Display*, XErrorVectorType>::iterator errors = xerrors.begin();
00282     for (; errors != xerrors.end(); ++errors)
00283         if (!xerror_handlers.count(errors->first))
00284             CheckErrors(errors->first);
00285 }
00286 
00287 #endif // USING_X11
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends