|
MythTV
0.26-pre
|
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
1.7.6.1