KDELibs4Support

kxerrorhandler.cpp
1 /*
2 
3  Copyright (c) 2003 Lubos Lunak <[email protected]>
4 
5  Permission is hereby granted, free of charge, to any person obtaining a
6  copy of this software and associated documentation files (the "Software"),
7  to deal in the Software without restriction, including without limitation
8  the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  and/or sell copies of the Software, and to permit persons to whom the
10  Software is furnished to do so, subject to the following conditions:
11 
12  The above copyright notice and this permission notice shall be included in
13  all copies or substantial portions of the Software.
14 
15  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  DEALINGS IN THE SOFTWARE.
22 
23 */
24 
25 #include "kxerrorhandler.h"
26 
27 #include "netwm_def.h"
28 
29 #include <stdio.h>
30 #include <QX11Info>
31 
32 class KXErrorHandlerPrivate
33 {
34 public:
35  KXErrorHandlerPrivate(Display *dpy) :
36  first_request(XNextRequest(dpy)),
37  display(dpy),
38  was_error(false)
39  {
40  }
41  unsigned long first_request;
42  Display *display;
43  bool was_error;
44  XErrorEvent error_event;
45 };
46 
47 KXErrorHandler **KXErrorHandler::handlers = nullptr;
48 int KXErrorHandler::pos = 0;
49 int KXErrorHandler::size = 0;
50 
52  : user_handler1(nullptr),
53  user_handler2(nullptr),
54  old_handler(XSetErrorHandler(handler_wrapper)),
55  d(new KXErrorHandlerPrivate(dpy))
56 {
57  addHandler();
58 }
59 
60 #ifndef KDELIBS4SUPPORT_NO_DEPRECATED
61 KXErrorHandler::KXErrorHandler(bool (*handler)(int request, int error_code, unsigned long resource_id), Display *dpy)
62  : user_handler1(handler),
63  user_handler2(nullptr),
64  old_handler(XSetErrorHandler(handler_wrapper)),
65  d(new KXErrorHandlerPrivate(dpy))
66 {
67  addHandler();
68 }
69 #endif
70 
71 KXErrorHandler::KXErrorHandler(int (*handler)(Display *, XErrorEvent *), Display *dpy)
72  : user_handler1(nullptr),
73  user_handler2(handler),
74  old_handler(XSetErrorHandler(handler_wrapper)),
75  d(new KXErrorHandlerPrivate(dpy))
76 {
77  addHandler();
78 }
79 
80 KXErrorHandler::~KXErrorHandler()
81 {
82  XSetErrorHandler(old_handler);
83  Q_ASSERT_X(this == handlers[ pos - 1 ], "KXErrorHandler", "out of order");
84  --pos;
85  delete d;
86 }
87 
88 void KXErrorHandler::addHandler()
89 {
90  if (size == pos) {
91  size += 16;
92  handlers = static_cast< KXErrorHandler ** >(realloc(handlers, size * sizeof(KXErrorHandler *)));
93  }
94  handlers[ pos++ ] = this;
95 }
96 
97 bool KXErrorHandler::error(bool sync) const
98 {
99  if (sync) {
100  XSync(d->display, False);
101  }
102  return d->was_error;
103 }
104 
105 XErrorEvent KXErrorHandler::errorEvent() const
106 {
107  return d->error_event;
108 }
109 
110 int KXErrorHandler::handler_wrapper(Display *dpy, XErrorEvent *e)
111 {
112  --pos;
113  int ret = handlers[ pos ]->handle(dpy, e);
114  ++pos;
115  return ret;
116 }
117 
118 int KXErrorHandler::handle(Display *dpy, XErrorEvent *e)
119 {
120  if (dpy == d->display
121  // e->serial >= d->first_request , compare like X timestamps to handle wrapping
122  && NET::timestampCompare(e->serial, d->first_request) >= 0) {
123  // it's for us
124  //qDebug( "Handling: %p", static_cast< void* >( this ));
125  bool error = false;
126  if (user_handler1 != nullptr) {
127  if (user_handler1(e->request_code, e->error_code, e->resourceid)) {
128  error = true;
129  }
130  } else if (user_handler2 != nullptr) {
131  if (user_handler2(dpy, e) != 0) {
132  error = true;
133  }
134  } else { // no handler set, simply set that there was an error
135  error = true;
136  }
137  if (error && !d->was_error) {
138  // only remember the first
139  d->was_error = true;
140  d->error_event = *e;
141  }
142  return 0;
143  }
144  //qDebug( "Going deeper: %p", static_cast< void* >( this ));
145  return old_handler(dpy, e);
146 }
147 
148 QByteArray KXErrorHandler::errorMessage(const XErrorEvent &event, Display *dpy)
149 {
150  // "Error: <error> (<value>), Request: <request>(<value>), Resource: <value>"
151  QByteArray ret;
152  char tmp[ 256 ];
153  char num[ 256 ];
154 #if 0 // see below
155  if (event.request_code < 128) // core request
156 #endif
157  {
158  XGetErrorText(dpy, event.error_code, tmp, 255);
159  if (char *paren = strchr(tmp, '(')) { // the explanation in parentheses just makes
160  *paren = '\0'; // it more verbose and is not really useful
161  }
162  // the various casts are to get overloads non-ambiguous :-/
163  ret = QByteArray("error: ") + (const char *)tmp + '[' + QByteArray::number(event.error_code) + ']';
164  sprintf(num, "%d", event.request_code);
165  XGetErrorDatabaseText(dpy, "XRequest", num, "<unknown>", tmp, 256);
166  ret += QByteArray(", request: ") + (const char *)tmp + '[' + QByteArray::number(event.request_code) + ']';
167  if (event.resourceid != 0) {
168  ret += QByteArray(", resource: 0x") + QByteArray::number((qlonglong)event.resourceid, 16);
169  }
170  }
171 #if 0
172  else { // extensions
173  // XGetErrorText() currently has a bug that makes it fail to find text
174  // for some errors (when error==error_base), also XGetErrorDatabaseText()
175  // requires the right extension name, so it is needed to get info about
176  // all extensions. However that is almost impossible:
177  // - Xlib itself has it, but in internal data.
178  // - Opening another X connection now can cause deadlock with server grabs.
179  // - Fetching it at startup means a bunch of roundtrips.
180  // So if this becomes more useful in the future, do the roundtrips at startup,
181  // or fetch it in kded and export as an env.var or something.
182  Display *dpy2 = XOpenDisplay(XDisplayString(dpy));
183  int nextensions;
184  char **extensions = XListExtensions(dpy2, &nextensions);
185  int *majors = NULL;
186  int *error_bases = NULL;
187  if (extensions == NULL) {
188  nextensions = 0;
189  } else {
190  majors = new int[ nextensions ];
191  error_bases = new int[ nextensions ];
192  for (int i = 0;
193  i < nextensions;
194  ++i) {
195  int dummy;
196  if (!XQueryExtension(dpy2, extensions[ i ], &majors[ i ], &dummy, &error_bases[ i ])) {
197  majors[ i ] = 0;
198  error_bases[ i ] = 0;
199  }
200  }
201  }
202  XGetErrorText(dpy, event.error_code, tmp, 255);
203  int index = -1;
204  int base = 0;
205  for (int i = 0;
206  i < nextensions;
207  ++i)
208  if (error_bases[ i ] != 0
209  && event.error_code >= error_bases[ i ] && (index == -1 || error_bases[ i ] > base)) {
210  index = i;
211  base = error_bases[ i ];
212  }
213  if (tmp == QString::number(event.error_code)) { // XGetErrorText() failed,
214  // or it has a bug that causes not finding all errors, check ourselves
215  if (index != -1) {
216  qsnprintf(num, 255, "%s.%d", extensions[ index ], event.error_code - base);
217  XGetErrorDatabaseText(dpy, "XProtoError", num, "<unknown>", tmp, 255);
218  } else {
219  strcpy(tmp, "<unknown>");
220  }
221  }
222  if (char *paren = strchr(tmp, '(')) {
223  *paren = '\0';
224  }
225  if (index != -1)
226  ret = QByteArray("error: ") + (const char *)tmp + '[' + (const char *)extensions[ index ]
227  + '+' + QByteArray::number(event.error_code - base) + ']';
228  else {
229  ret = QByteArray("error: ") + (const char *)tmp + '[' + QByteArray::number(event.error_code) + ']';
230  }
231  tmp[ 0 ] = '\0';
232  for (int i = 0;
233  i < nextensions;
234  ++i)
235  if (majors[ i ] == event.request_code) {
236  qsnprintf(num, 255, "%s.%d", extensions[ i ], event.minor_code);
237  XGetErrorDatabaseText(dpy, "XRequest", num, "<unknown>", tmp, 255);
238  ret += QByteArray(", request: ") + (const char *)tmp + '[' + (const char *)extensions[ i ] + '+'
239  + QByteArray::number(event.minor_code) + ']';
240  }
241  if (tmp[ 0 ] == '\0') // not found???
242  ret += QByteArray(", request <unknown> [") + QByteArray::number(event.request_code) + ':'
243  + QByteArray::number(event.minor_code) + ']';
244  if (event.resourceid != 0) {
245  ret += QByteArray(", resource: 0x") + QByteArray::number((qlonglong)event.resourceid, 16);
246  }
247  if (extensions != NULL) {
248  XFreeExtensionList(extensions);
249  }
250  delete[] majors;
251  delete[] error_bases;
252  XCloseDisplay(dpy2);
253  }
254 #endif
255  return ret;
256 }
257 
259 {
260  return QX11Info::display();
261 }
bool error(bool sync) const
This function returns true if the error flag is set (i.e.
XErrorEvent errorEvent() const
This function returns the error event for the first X error that occurred.
KXErrorHandler(Display *dpy=display())
Creates error handler that will set error flag after encountering any X error.
static int timestampCompare(unsigned long time1, unsigned long time2)
QString number(int n, int base)
static Display * display()
This function simply wraps QX11Info::display(), to make sure the public interface doesn&#39;t require QtX...
QByteArray number(int n, int base)
This class simplifies handling of X errors.
static QByteArray errorMessage(const XErrorEvent &e, Display *dpy=display())
Returns error message for the given error.
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Aug 3 2020 22:58:01 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.