2014-11-13 01:04:59 +02:00
|
|
|
/*
|
|
|
|
|
|
|
|
Copyright (c) 2003 Lubos Lunak <l.lunak@kde.org>
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
copy of this software and associated documentation files (the "Software"),
|
|
|
|
to deal in the Software without restriction, including without limitation
|
|
|
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
|
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
|
|
DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "kxerrorhandler.h"
|
|
|
|
#include "netwm_def.h"
|
|
|
|
|
2022-10-19 02:31:20 +03:00
|
|
|
#include <string.h>
|
2014-11-13 01:04:59 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2022-10-19 02:31:20 +03:00
|
|
|
static const ushort s_xerrorbuffsize = 256;
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
class KXErrorHandlerPrivate
|
|
|
|
{
|
|
|
|
public:
|
2022-10-19 02:07:41 +03:00
|
|
|
KXErrorHandlerPrivate(Display* dpy);
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
unsigned long first_request;
|
|
|
|
Display* display;
|
|
|
|
bool was_error;
|
|
|
|
XErrorEvent error_event;
|
|
|
|
};
|
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
KXErrorHandlerPrivate::KXErrorHandlerPrivate(Display* dpy)
|
|
|
|
: first_request(XNextRequest(dpy)),
|
|
|
|
display(dpy),
|
|
|
|
was_error(false)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-13 01:04:59 +02:00
|
|
|
KXErrorHandler** KXErrorHandler::handlers = NULL;
|
|
|
|
int KXErrorHandler::pos = 0;
|
|
|
|
int KXErrorHandler::size = 0;
|
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
KXErrorHandler::KXErrorHandler(Display* dpy)
|
2022-10-19 02:12:13 +03:00
|
|
|
: user_handler(NULL),
|
2022-10-19 02:07:41 +03:00
|
|
|
old_handler(XSetErrorHandler(handler_wrapper)),
|
|
|
|
d( new KXErrorHandlerPrivate(dpy))
|
|
|
|
{
|
2014-11-13 01:04:59 +02:00
|
|
|
addHandler();
|
2022-10-19 02:07:41 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
KXErrorHandler::KXErrorHandler(int (*handler)(Display*, XErrorEvent*), Display* dpy)
|
2022-10-19 02:12:13 +03:00
|
|
|
: user_handler(handler),
|
2022-10-19 02:07:41 +03:00
|
|
|
old_handler(XSetErrorHandler(handler_wrapper)),
|
|
|
|
d(new KXErrorHandlerPrivate(dpy))
|
|
|
|
{
|
2014-11-13 01:04:59 +02:00
|
|
|
addHandler();
|
2022-10-19 02:07:41 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
KXErrorHandler::~KXErrorHandler()
|
2022-10-19 02:07:41 +03:00
|
|
|
{
|
|
|
|
XSetErrorHandler(old_handler);
|
|
|
|
Q_ASSERT_X(this == handlers[pos - 1], "KXErrorHandler", "out of order");
|
2014-11-13 01:04:59 +02:00
|
|
|
--pos;
|
|
|
|
delete d;
|
2022-10-19 02:07:41 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
void KXErrorHandler::addHandler()
|
2022-10-19 02:07:41 +03:00
|
|
|
{
|
|
|
|
if (size == pos) {
|
2014-11-13 01:04:59 +02:00
|
|
|
size += 16;
|
2022-10-19 02:07:41 +03:00
|
|
|
handlers = static_cast<KXErrorHandler**>(::realloc(handlers, size * sizeof(KXErrorHandler*)));
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
2022-10-19 02:07:41 +03:00
|
|
|
handlers[pos++] = this;
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
bool KXErrorHandler::error(bool sync) const
|
|
|
|
{
|
|
|
|
if (sync) {
|
|
|
|
XSync(d->display, False);
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
2022-10-19 02:07:41 +03:00
|
|
|
return d->was_error;
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
|
|
|
XErrorEvent KXErrorHandler::errorEvent() const
|
2022-10-19 02:07:41 +03:00
|
|
|
{
|
2014-11-13 01:04:59 +02:00
|
|
|
return d->error_event;
|
2022-10-19 02:07:41 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
int KXErrorHandler::handler_wrapper(Display* dpy, XErrorEvent* e)
|
|
|
|
{
|
2014-11-13 01:04:59 +02:00
|
|
|
--pos;
|
2022-10-19 02:07:41 +03:00
|
|
|
int ret = handlers[pos]->handle(dpy, e);
|
2014-11-13 01:04:59 +02:00
|
|
|
++pos;
|
|
|
|
return ret;
|
2022-10-19 02:07:41 +03:00
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
int KXErrorHandler::handle(Display* dpy, XErrorEvent* e)
|
|
|
|
{
|
|
|
|
if (dpy == d->display
|
2014-11-13 01:04:59 +02:00
|
|
|
// e->serial >= d->first_request , compare like X timestamps to handle wrapping
|
2022-10-19 02:07:41 +03:00
|
|
|
&& NET::timestampCompare(e->serial, d->first_request) >= 0) {
|
|
|
|
// it's for us
|
2022-10-19 02:12:13 +03:00
|
|
|
// qDebug("Handling: %p", static_cast<void*>(this));
|
2014-11-13 01:04:59 +02:00
|
|
|
bool error = false;
|
2022-10-19 02:12:13 +03:00
|
|
|
if (user_handler != NULL) {
|
|
|
|
if (user_handler(dpy, e) != 0) {
|
2014-11-13 01:04:59 +02:00
|
|
|
error = true;
|
|
|
|
}
|
2022-10-19 02:07:41 +03:00
|
|
|
} else {
|
|
|
|
// no handler set, simply set that there was an error
|
2014-11-13 01:04:59 +02:00
|
|
|
error = true;
|
2022-10-19 02:07:41 +03:00
|
|
|
}
|
|
|
|
if (error && !d->was_error) {
|
|
|
|
// only remember the first
|
2014-11-13 01:04:59 +02:00
|
|
|
d->was_error = true;
|
|
|
|
d->error_event = *e;
|
|
|
|
}
|
2022-10-19 02:07:41 +03:00
|
|
|
return 0;
|
2014-11-13 01:04:59 +02:00
|
|
|
}
|
2022-10-19 02:07:41 +03:00
|
|
|
// qDebug( "Going deeper: %p", static_cast< void* >( this ));
|
|
|
|
return old_handler(dpy, e);
|
|
|
|
}
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-10-19 02:31:20 +03:00
|
|
|
QByteArray KXErrorHandler::errorMessage(const XErrorEvent& event, Display* dpy)
|
|
|
|
{
|
|
|
|
// "Error: <error> (<value>), Request: <request>(<value>), Resource: <value>"
|
|
|
|
char xerrorbuff[s_xerrorbuffsize];
|
|
|
|
::memset(xerrorbuff, '\0', s_xerrorbuffsize * sizeof(char));
|
|
|
|
XGetErrorText(dpy, event.error_code, xerrorbuff, s_xerrorbuffsize - 1);
|
2014-11-13 01:04:59 +02:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
// the explanation in parentheses just makes it more verbose and is not really useful
|
2022-10-19 02:31:20 +03:00
|
|
|
if (char* paren = strchr(xerrorbuff, '(' )) {
|
2022-10-19 02:07:41 +03:00
|
|
|
*paren = '\0';
|
|
|
|
}
|
2022-10-19 02:31:20 +03:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
// the various casts are to get overloads non-ambiguous :-/
|
2022-10-19 02:31:20 +03:00
|
|
|
QByteArray ret = QByteArray("error: ") + (const char*)xerrorbuff + '[' + QByteArray::number(event.error_code) + ']';
|
|
|
|
|
|
|
|
char xrequestbuff[s_xerrorbuffsize];
|
|
|
|
::memset(xrequestbuff, '\0', s_xerrorbuffsize * sizeof(char));
|
|
|
|
::sprintf(xrequestbuff, "%d", event.request_code);
|
|
|
|
::memset(xerrorbuff, '\0', s_xerrorbuffsize * sizeof(char));
|
|
|
|
XGetErrorDatabaseText(dpy, "XRequest", xrequestbuff, "<unknown>", xerrorbuff, s_xerrorbuffsize);
|
|
|
|
|
|
|
|
ret += QByteArray(", request: ") + (const char*)xerrorbuff + '[' + QByteArray::number(event.request_code) + ']';
|
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
if (event.resourceid != 0) {
|
|
|
|
ret += QByteArray(", resource: 0x") + QByteArray::number((qlonglong)event.resourceid, 16);
|
|
|
|
}
|
2022-10-19 02:31:20 +03:00
|
|
|
|
2022-10-19 02:07:41 +03:00
|
|
|
return ret;
|
|
|
|
}
|