Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org>
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "kxerrorhandler_p.h"
|
||||
#include <config-kwindowsystem.h>
|
||||
|
||||
#include <fixx11h.h>
|
||||
|
||||
#include "netwm_def.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
|
||||
class KXErrorHandlerPrivate
|
||||
{
|
||||
public:
|
||||
KXErrorHandlerPrivate(Display *dpy)
|
||||
: first_request(XNextRequest(dpy))
|
||||
, display(dpy)
|
||||
, was_error(false)
|
||||
{
|
||||
}
|
||||
unsigned long first_request;
|
||||
Display *display;
|
||||
bool was_error;
|
||||
XErrorEvent error_event;
|
||||
};
|
||||
|
||||
KXErrorHandler **KXErrorHandler::handlers = nullptr;
|
||||
int KXErrorHandler::pos = 0;
|
||||
int KXErrorHandler::size = 0;
|
||||
|
||||
KXErrorHandler::KXErrorHandler(Display *dpy)
|
||||
: user_handler1(nullptr)
|
||||
, user_handler2(nullptr)
|
||||
, old_handler(XSetErrorHandler(handler_wrapper))
|
||||
, d(new KXErrorHandlerPrivate(dpy))
|
||||
{
|
||||
addHandler();
|
||||
}
|
||||
|
||||
KXErrorHandler::KXErrorHandler(int (*handler)(Display *, XErrorEvent *), Display *dpy)
|
||||
: user_handler1(nullptr)
|
||||
, user_handler2(handler)
|
||||
, old_handler(XSetErrorHandler(handler_wrapper))
|
||||
, d(new KXErrorHandlerPrivate(dpy))
|
||||
{
|
||||
addHandler();
|
||||
}
|
||||
|
||||
KXErrorHandler::~KXErrorHandler()
|
||||
{
|
||||
XSetErrorHandler(old_handler);
|
||||
Q_ASSERT_X(this == handlers[pos - 1], "KXErrorHandler", "out of order");
|
||||
--pos;
|
||||
delete d;
|
||||
}
|
||||
|
||||
void KXErrorHandler::addHandler()
|
||||
{
|
||||
if (size == pos) {
|
||||
size += 16;
|
||||
handlers = static_cast<KXErrorHandler **>(realloc(handlers, size * sizeof(KXErrorHandler *)));
|
||||
}
|
||||
handlers[pos++] = this;
|
||||
}
|
||||
|
||||
bool KXErrorHandler::error(bool sync) const
|
||||
{
|
||||
if (sync) {
|
||||
XSync(d->display, False);
|
||||
}
|
||||
return d->was_error;
|
||||
}
|
||||
|
||||
XErrorEvent KXErrorHandler::errorEvent() const
|
||||
{
|
||||
return d->error_event;
|
||||
}
|
||||
|
||||
int KXErrorHandler::handler_wrapper(Display *dpy, XErrorEvent *e)
|
||||
{
|
||||
--pos;
|
||||
int ret = handlers[pos]->handle(dpy, e);
|
||||
++pos;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int KXErrorHandler::handle(Display *dpy, XErrorEvent *e)
|
||||
{
|
||||
if (dpy == d->display
|
||||
// e->serial >= d->first_request , compare like X timestamps to handle wrapping
|
||||
&& NET::timestampCompare(e->serial, d->first_request) >= 0) {
|
||||
// it's for us
|
||||
// qDebug( "Handling: %p", static_cast< void* >( this ));
|
||||
bool error = false;
|
||||
if (user_handler1 != nullptr) {
|
||||
if (user_handler1(e->request_code, e->error_code, e->resourceid)) {
|
||||
error = true;
|
||||
}
|
||||
} else if (user_handler2 != nullptr) {
|
||||
if (user_handler2(dpy, e) != 0) {
|
||||
error = true;
|
||||
}
|
||||
} else { // no handler set, simply set that there was an error
|
||||
error = true;
|
||||
}
|
||||
if (error && !d->was_error) {
|
||||
// only remember the first
|
||||
d->was_error = true;
|
||||
d->error_event = *e;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// qDebug( "Going deeper: %p", static_cast< void* >( this ));
|
||||
return old_handler(dpy, e);
|
||||
}
|
||||
|
||||
QByteArray KXErrorHandler::errorMessage(const XErrorEvent &event, Display *dpy)
|
||||
{
|
||||
// "Error: <error> (<value>), Request: <request>(<value>), Resource: <value>"
|
||||
QByteArray ret;
|
||||
char tmp[256];
|
||||
#if 0 // see below
|
||||
char num[ 256 ];
|
||||
if (event.request_code < 128) // core request
|
||||
#endif
|
||||
{
|
||||
XGetErrorText(dpy, event.error_code, tmp, 255);
|
||||
if (char *paren = strchr(tmp, '(')) { // the explanation in parentheses just makes
|
||||
*paren = '\0'; // it more verbose and is not really useful
|
||||
}
|
||||
// the various casts are to get overloads non-ambiguous :-/
|
||||
/*
|
||||
ret = QByteArray("error: ") + (const char *)tmp + '[' + QByteArray::number(event.error_code) + ']';
|
||||
sprintf(num, "%d", event.request_code);
|
||||
XGetErrorDatabaseText(dpy, "XRequest", num, "<unknown>", tmp, 256);
|
||||
ret += QByteArray(", request: ") + (const char *)tmp + '[' + QByteArray::number(event.request_code) + ']';
|
||||
if (event.resourceid != 0) {
|
||||
ret += QByteArray(", resource: 0x") + QByteArray::number((qlonglong)event.resourceid, 16);
|
||||
}
|
||||
*/
|
||||
}
|
||||
#if 0
|
||||
else { // extensions
|
||||
// XGetErrorText() currently has a bug that makes it fail to find text
|
||||
// for some errors (when error==error_base), also XGetErrorDatabaseText()
|
||||
// requires the right extension name, so it is needed to get info about
|
||||
// all extensions. However that is almost impossible:
|
||||
// - Xlib itself has it, but in internal data.
|
||||
// - Opening another X connection now can cause deadlock with server grabs.
|
||||
// - Fetching it at startup means a bunch of roundtrips.
|
||||
// So if this becomes more useful in the future, do the roundtrips at startup,
|
||||
// or fetch it in kded and export as an env.var or something.
|
||||
Display *dpy2 = XOpenDisplay(XDisplayString(dpy));
|
||||
int nextensions;
|
||||
char **extensions = XListExtensions(dpy2, &nextensions);
|
||||
int *majors = nullptr;
|
||||
int *error_bases = nullptr;
|
||||
if (extensions == nullptr) {
|
||||
nextensions = 0;
|
||||
} else {
|
||||
majors = new int[ nextensions ];
|
||||
error_bases = new int[ nextensions ];
|
||||
for (int i = 0;
|
||||
i < nextensions;
|
||||
++i) {
|
||||
int dummy;
|
||||
if (!XQueryExtension(dpy2, extensions[ i ], &majors[ i ], &dummy, &error_bases[ i ])) {
|
||||
majors[ i ] = 0;
|
||||
error_bases[ i ] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
XGetErrorText(dpy, event.error_code, tmp, 255);
|
||||
int index = -1;
|
||||
int base = 0;
|
||||
for (int i = 0;
|
||||
i < nextensions;
|
||||
++i)
|
||||
if (error_bases[ i ] != 0
|
||||
&& event.error_code >= error_bases[ i ] && (index == -1 || error_bases[ i ] > base)) {
|
||||
index = i;
|
||||
base = error_bases[ i ];
|
||||
}
|
||||
if (tmp == QString::number(event.error_code)) { // XGetErrorText() failed,
|
||||
// or it has a bug that causes not finding all errors, check ourselves
|
||||
if (index != -1) {
|
||||
qsnprintf(num, 255, "%s.%d", extensions[ index ], event.error_code - base);
|
||||
XGetErrorDatabaseText(dpy, "XProtoError", num, "<unknown>", tmp, 255);
|
||||
} else {
|
||||
strcpy(tmp, "<unknown>");
|
||||
}
|
||||
}
|
||||
if (char *paren = strchr(tmp, '(')) {
|
||||
*paren = '\0';
|
||||
}
|
||||
if (index != -1)
|
||||
ret = QByteArray("error: ") + (const char *)tmp + '[' + (const char *)extensions[ index ]
|
||||
+ '+' + QByteArray::number(event.error_code - base) + ']';
|
||||
else {
|
||||
ret = QByteArray("error: ") + (const char *)tmp + '[' + QByteArray::number(event.error_code) + ']';
|
||||
}
|
||||
tmp[ 0 ] = '\0';
|
||||
for (int i = 0;
|
||||
i < nextensions;
|
||||
++i)
|
||||
if (majors[ i ] == event.request_code) {
|
||||
qsnprintf(num, 255, "%s.%d", extensions[ i ], event.minor_code);
|
||||
XGetErrorDatabaseText(dpy, "XRequest", num, "<unknown>", tmp, 255);
|
||||
ret += QByteArray(", request: ") + (const char *)tmp + '[' + (const char *)extensions[ i ] + '+'
|
||||
+ QByteArray::number(event.minor_code) + ']';
|
||||
}
|
||||
if (tmp[ 0 ] == '\0') // not found???
|
||||
ret += QByteArray(", request <unknown> [") + QByteArray::number(event.request_code) + ':'
|
||||
+ QByteArray::number(event.minor_code) + ']';
|
||||
if (event.resourceid != 0) {
|
||||
ret += QByteArray(", resource: 0x") + QByteArray::number((qlonglong)event.resourceid, 16);
|
||||
}
|
||||
if (extensions != nullptr) {
|
||||
XFreeExtensionList(extensions);
|
||||
}
|
||||
delete[] majors;
|
||||
delete[] error_bases;
|
||||
XCloseDisplay(dpy2);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
Reference in New Issue
Block a user