KDEUI
kxerrorhandler.cpp
Go to the documentation of this file.
00001 /* 00002 00003 Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org> 00004 00005 Permission is hereby granted, free of charge, to any person obtaining a 00006 copy of this software and associated documentation files (the "Software"), 00007 to deal in the Software without restriction, including without limitation 00008 the rights to use, copy, modify, merge, publish, distribute, sublicense, 00009 and/or sell copies of the Software, and to permit persons to whom the 00010 Software is furnished to do so, subject to the following conditions: 00011 00012 The above copyright notice and this permission notice shall be included in 00013 all copies or substantial portions of the Software. 00014 00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 00018 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00019 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 00020 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 00021 DEALINGS IN THE SOFTWARE. 00022 00023 */ 00024 00025 #include "kxerrorhandler.h" 00026 00027 #ifdef Q_WS_X11 //FIXME 00028 00029 #include "netwm_def.h" 00030 00031 #include <stdio.h> 00032 00033 class KXErrorHandlerPrivate 00034 { 00035 public: 00036 KXErrorHandlerPrivate( Display* dpy ) : 00037 first_request( XNextRequest( dpy )), 00038 display( dpy ), 00039 was_error( false ) 00040 { 00041 } 00042 unsigned long first_request; 00043 Display* display; 00044 bool was_error; 00045 XErrorEvent error_event; 00046 }; 00047 00048 KXErrorHandler** KXErrorHandler::handlers = NULL; 00049 int KXErrorHandler::pos = 0; 00050 int KXErrorHandler::size = 0; 00051 00052 KXErrorHandler::KXErrorHandler( Display* dpy ) 00053 : user_handler1( NULL ), 00054 user_handler2( NULL ), 00055 old_handler( XSetErrorHandler( handler_wrapper )), 00056 d( new KXErrorHandlerPrivate(dpy) ) 00057 { 00058 addHandler(); 00059 } 00060 00061 #ifndef KDE_NO_DEPRECATED 00062 KXErrorHandler::KXErrorHandler( bool (*handler)( int request, int error_code, unsigned long resource_id ), Display* dpy ) 00063 : user_handler1( handler ), 00064 user_handler2( NULL ), 00065 old_handler( XSetErrorHandler( handler_wrapper )), 00066 d( new KXErrorHandlerPrivate(dpy) ) 00067 { 00068 addHandler(); 00069 } 00070 #endif 00071 00072 KXErrorHandler::KXErrorHandler( int (*handler)( Display*, XErrorEvent* ), Display* dpy ) 00073 : user_handler1( NULL ), 00074 user_handler2( handler ), 00075 old_handler( XSetErrorHandler( handler_wrapper )), 00076 d( new KXErrorHandlerPrivate(dpy) ) 00077 { 00078 addHandler(); 00079 } 00080 00081 KXErrorHandler::~KXErrorHandler() 00082 { 00083 XSetErrorHandler( old_handler ); 00084 Q_ASSERT_X( this == handlers[ pos-1 ], "KXErrorHandler", "out of order" ); 00085 --pos; 00086 delete d; 00087 } 00088 00089 void KXErrorHandler::addHandler() 00090 { 00091 if( size == pos ) 00092 { 00093 size += 16; 00094 handlers = static_cast< KXErrorHandler** >( qRealloc( handlers, size * sizeof( KXErrorHandler* ))); 00095 } 00096 handlers[ pos++ ] = this; 00097 } 00098 00099 bool KXErrorHandler::error( bool sync ) const 00100 { 00101 if( sync ) 00102 XSync( d->display, False ); 00103 return d->was_error; 00104 } 00105 00106 XErrorEvent KXErrorHandler::errorEvent() const 00107 { 00108 return d->error_event; 00109 } 00110 00111 int KXErrorHandler::handler_wrapper( Display* dpy, XErrorEvent* e ) 00112 { 00113 --pos; 00114 int ret = handlers[ pos ]->handle( dpy, e ); 00115 ++pos; 00116 return ret; 00117 } 00118 00119 int KXErrorHandler::handle( Display* dpy, XErrorEvent* e ) 00120 { 00121 if( dpy == d->display 00122 // e->serial >= d->first_request , compare like X timestamps to handle wrapping 00123 && NET::timestampCompare( e->serial, d->first_request ) >= 0 ) 00124 { // it's for us 00125 //qDebug( "Handling: %p", static_cast< void* >( this )); 00126 bool error = false; 00127 if( user_handler1 != NULL ) 00128 { 00129 if( user_handler1( e->request_code, e->error_code, e->resourceid )) 00130 error = true; 00131 } 00132 else if( user_handler2 != NULL ) 00133 { 00134 if( user_handler2( dpy, e ) != 0 ) 00135 error = true; 00136 } 00137 else // no handler set, simply set that there was an error 00138 error = true; 00139 if( error && !d->was_error ) 00140 { // only remember the first 00141 d->was_error = true; 00142 d->error_event = *e; 00143 } 00144 return 0; 00145 } 00146 //qDebug( "Going deeper: %p", static_cast< void* >( this )); 00147 return old_handler( dpy, e ); 00148 } 00149 00150 QByteArray KXErrorHandler::errorMessage( const XErrorEvent& event, Display* dpy ) 00151 { // "Error: <error> (<value>), Request: <request>(<value>), Resource: <value>" 00152 QByteArray ret; 00153 char tmp[ 256 ]; 00154 char num[ 256 ]; 00155 #if 0 // see below 00156 if( event.request_code < 128 ) // core request 00157 #endif 00158 { 00159 XGetErrorText( dpy, event.error_code, tmp, 255 ); 00160 if( char* paren = strchr( tmp, '(' )) // the explanation in parentheses just makes 00161 *paren = '\0'; // it more verbose and is not really useful 00162 // the various casts are to get overloads non-ambiguous :-/ 00163 ret = QByteArray( "error: " ) + (const char*)tmp + '[' + QByteArray::number( event.error_code ) + ']'; 00164 sprintf( num, "%d", event.request_code ); 00165 XGetErrorDatabaseText( dpy, "XRequest", num, "<unknown>", tmp, 256 ); 00166 ret += QByteArray( ", request: " ) + (const char*)tmp + '[' + QByteArray::number( event.request_code ) + ']'; 00167 if( event.resourceid != 0 ) 00168 ret += QByteArray( ", resource: 0x" ) + QByteArray::number( (qlonglong)event.resourceid, 16 ); 00169 } 00170 #if 0 00171 else // extensions 00172 { 00173 // XGetErrorText() currently has a bug that makes it fail to find text 00174 // for some errors (when error==error_base), also XGetErrorDatabaseText() 00175 // requires the right extension name, so it is needed to get info about 00176 // all extensions. However that is almost impossible: 00177 // - Xlib itself has it, but in internal data. 00178 // - Opening another X connection now can cause deadlock with server grabs. 00179 // - Fetching it at startup means a bunch of roundtrips. 00180 // So if this becomes more useful in the future, do the roundtrips at startup, 00181 // or fetch it in kded and export as an env.var or something. 00182 Display* dpy2 = XOpenDisplay( XDisplayString( dpy )); 00183 int nextensions; 00184 char** extensions = XListExtensions( dpy2, &nextensions ); 00185 int* majors = NULL; 00186 int* error_bases = NULL; 00187 if( extensions == NULL ) 00188 nextensions = 0; 00189 else 00190 { 00191 majors = new int[ nextensions ]; 00192 error_bases = new int[ nextensions ]; 00193 for( int i = 0; 00194 i < nextensions; 00195 ++i ) 00196 { 00197 int dummy; 00198 if( !XQueryExtension( dpy2, extensions[ i ], &majors[ i ], &dummy, &error_bases[ i ] )) 00199 { 00200 majors[ i ] = 0; 00201 error_bases[ i ] = 0; 00202 } 00203 } 00204 } 00205 XGetErrorText( dpy, event.error_code, tmp, 255 ); 00206 int index = -1; 00207 int base = 0; 00208 for( int i = 0; 00209 i < nextensions; 00210 ++i ) 00211 if( error_bases[ i ] != 0 00212 && event.error_code >= error_bases[ i ] && ( index == -1 || error_bases[ i ] > base )) 00213 { 00214 index = i; 00215 base = error_bases[ i ]; 00216 } 00217 if( tmp == QString::number( event.error_code )) // XGetErrorText() failed, 00218 { // or it has a bug that causes not finding all errors, check ourselves 00219 if( index != -1 ) 00220 { 00221 snprintf( num, 255, "%s.%d", extensions[ index ], event.error_code - base ); 00222 XGetErrorDatabaseText( dpy, "XProtoError", num, "<unknown>", tmp, 255 ); 00223 } 00224 else 00225 strcpy( tmp, "<unknown>" ); 00226 } 00227 if( char* paren = strchr( tmp, '(' )) 00228 *paren = '\0'; 00229 if( index != -1 ) 00230 ret = QByteArray( "error: " ) + (const char*)tmp + '[' + (const char*)extensions[ index ] 00231 + '+' + QByteArray::number( event.error_code - base ) + ']'; 00232 else 00233 ret = QByteArray( "error: " ) + (const char*)tmp + '[' + QByteArray::number( event.error_code ) + ']'; 00234 tmp[ 0 ] = '\0'; 00235 for( int i = 0; 00236 i < nextensions; 00237 ++i ) 00238 if( majors[ i ] == event.request_code ) 00239 { 00240 snprintf( num, 255, "%s.%d", extensions[ i ], event.minor_code ); 00241 XGetErrorDatabaseText( dpy, "XRequest", num, "<unknown>", tmp, 255 ); 00242 ret += QByteArray( ", request: " ) + (const char*)tmp + '[' + (const char*)extensions[ i ] + '+' 00243 + QByteArray::number( event.minor_code ) + ']'; 00244 } 00245 if( tmp[ 0 ] == '\0' ) // not found??? 00246 ret += QByteArray( ", request <unknown> [" ) + QByteArray::number( event.request_code ) + ':' 00247 + QByteArray::number( event.minor_code ) + ']'; 00248 if( event.resourceid != 0 ) 00249 ret += QByteArray( ", resource: 0x" ) + QByteArray::number( (qlonglong)event.resourceid, 16 ); 00250 if( extensions != NULL ) 00251 XFreeExtensionList( extensions ); 00252 delete[] majors; 00253 delete[] error_bases; 00254 XCloseDisplay( dpy2 ); 00255 } 00256 #endif 00257 return ret; 00258 } 00259 00260 #endif
KDE 4.6 API Reference