1 | /* |
2 | SPDX-FileCopyrightText: 2003 Lubos Lunak <l.lunak@kde.org> |
3 | |
4 | SPDX-License-Identifier: MIT |
5 | */ |
6 | |
7 | #ifndef KXERRORHANDLER_H |
8 | #define KXERRORHANDLER_H |
9 | #include <config-kwindowsystem.h> |
10 | |
11 | #include <mutex> |
12 | |
13 | #include <QtGlobal> |
14 | |
15 | #include <private/qtx11extras_p.h> |
16 | |
17 | #include <X11/Xlib.h> |
18 | |
19 | class KXErrorHandlerPrivate; |
20 | /*! |
21 | * This class simplifies handling of X errors. It shouldn't be necessary to use |
22 | * with Qt classes, as the toolkit should handle X errors itself, so this |
23 | * class will be mainly used with direct Xlib usage, and some lowlevel classes |
24 | * like NETWinInfo. |
25 | * |
26 | * The usual usage is to create a KXErrorHandler instance right before starting |
27 | * operations that might cause X errors, and checking if there was an error |
28 | * by calling error() after the operations are finished. The handlers |
29 | * may be nested, but must be destroyed in reverse order they were created. |
30 | * |
31 | * There's no need to do X sync before creating an instance, every instance |
32 | * will handle only errors for request issued after the instance was created. |
33 | * Errors for older requests will be passed to previous error handler. |
34 | * When checking for error by calling error() at the end, it is necessary |
35 | * to sync with X, to catch all errors that were caused by requests issued |
36 | * before the call to error(). This can be done by passing true to error() |
37 | * to cause explicit XSync(), however, if the last X request needed a roundtrip |
38 | * (e.g. XGetWindowAttributes(), XGetGeometry(), etc.), it is not required |
39 | * to do an explicit sync. |
40 | * |
41 | * \internal |
42 | */ |
43 | class KXErrorHandler |
44 | { |
45 | public: |
46 | /*! |
47 | * Creates error handler that will set error flag after encountering |
48 | * any X error. |
49 | */ |
50 | explicit KXErrorHandler(Display *dpy = QX11Info::display()); |
51 | /*! |
52 | * This constructor takes pointer to a function whose prototype matches |
53 | * the one that's used with the XSetErrorHandler() Xlib function. |
54 | * NOTE: For the error flag to be set, the function must return a non-zero |
55 | * value. |
56 | */ |
57 | explicit KXErrorHandler(int (*handler)(Display *, XErrorEvent *), Display *dpy = QX11Info::display()); |
58 | /*! |
59 | * This function returns true if the error flag is set (i.e. no custom handler |
60 | * function was used and there was any error, or the custom handler indicated |
61 | * an error by its return value). |
62 | * |
63 | * \a sync if true, an explicit XSync() will be done. Not necessary |
64 | * when the last X request required a roundtrip. |
65 | */ |
66 | bool error(bool sync) const; |
67 | /*! |
68 | * This function returns the error event for the first X error that occurred. |
69 | * The return value is useful only if error() returned true. |
70 | * \since 4.0.1 |
71 | */ |
72 | XErrorEvent errorEvent() const; |
73 | /*! |
74 | * Returns error message for the given error. The error message is not translated, |
75 | * as it is meant for debugging. |
76 | * \since 4.0.1 |
77 | */ |
78 | static QByteArray errorMessage(const XErrorEvent &e, Display *dpy = QX11Info::display()); |
79 | ~KXErrorHandler(); |
80 | |
81 | private: |
82 | void addHandler(); |
83 | int handle(Display *dpy, XErrorEvent *e); |
84 | bool (*user_handler1)(int request, int error_code, unsigned long resource_id); |
85 | int (*user_handler2)(Display *, XErrorEvent *); |
86 | int (*old_handler)(Display *, XErrorEvent *); |
87 | static int handler_wrapper(Display *, XErrorEvent *); |
88 | static std::mutex s_lock; |
89 | static KXErrorHandler **handlers; |
90 | static int pos; |
91 | static int size; |
92 | Q_DISABLE_COPY(KXErrorHandler) |
93 | KXErrorHandlerPrivate *const d; |
94 | }; |
95 | |
96 | #endif |
97 | |