Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: sw=2 ts=8 et :
3 : */
4 : /* This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 :
8 : #ifndef mozilla_X11Util_h
9 : #define mozilla_X11Util_h
10 :
11 : // Utilities common to all X clients, regardless of UI toolkit.
12 :
13 : #if defined(MOZ_WIDGET_GTK)
14 : # include <gdk/gdk.h>
15 : # include <gdk/gdkx.h>
16 : # include "X11UndefineNone.h"
17 : #else
18 : # error Unknown toolkit
19 : #endif
20 :
21 : #include <string.h> // for memset
22 : #include "mozilla/Scoped.h" // for SCOPED_TEMPLATE
23 :
24 : namespace mozilla {
25 :
26 : /**
27 : * Return the default X Display created and used by the UI toolkit.
28 : */
29 : inline Display*
30 2 : DefaultXDisplay()
31 : {
32 : #if defined(MOZ_WIDGET_GTK)
33 2 : return GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
34 : #endif
35 : }
36 :
37 : /**
38 : * Sets *aVisual to point to aDisplay's Visual struct corresponding to
39 : * aVisualID, and *aDepth to its depth. When aVisualID is None, these are set
40 : * to nullptr and 0 respectively. Both out-parameter pointers are assumed
41 : * non-nullptr.
42 : */
43 : void
44 : FindVisualAndDepth(Display* aDisplay, VisualID aVisualID,
45 : Visual** aVisual, int* aDepth);
46 :
47 :
48 : /**
49 : * Ensure that all X requests have been processed.
50 : *
51 : * This is similar to XSync, but doesn't need a round trip if the previous
52 : * request was synchronous or if events have been received since the last
53 : * request. Subsequent FinishX calls will be noops if there have been no
54 : * intermediate requests.
55 : */
56 :
57 : void
58 : FinishX(Display* aDisplay);
59 :
60 : /**
61 : * Invoke XFree() on a pointer to memory allocated by Xlib (if the
62 : * pointer is nonnull) when this class goes out of scope.
63 : */
64 : template <typename T>
65 : struct ScopedXFreePtrTraits
66 : {
67 : typedef T *type;
68 0 : static T *empty() { return nullptr; }
69 0 : static void release(T *ptr) { if (ptr != nullptr) XFree(ptr); }
70 : };
71 0 : SCOPED_TEMPLATE(ScopedXFree, ScopedXFreePtrTraits)
72 :
73 : /**
74 : * On construction, set a graceful X error handler that doesn't crash the application and records X errors.
75 : * On destruction, restore the X error handler to what it was before construction.
76 : *
77 : * The SyncAndGetError() method allows to know whether a X error occurred, optionally allows to get the full XErrorEvent,
78 : * and resets the recorded X error state so that a single X error will be reported only once.
79 : *
80 : * Nesting is correctly handled: multiple nested ScopedXErrorHandler's don't interfere with each other's state. However,
81 : * if SyncAndGetError is not called on the nested ScopedXErrorHandler, then any X errors caused by X calls made while the nested
82 : * ScopedXErrorHandler was in place may then be caught by the other ScopedXErrorHandler. This is just a result of X being
83 : * asynchronous and us not doing any implicit syncing: the only method in this class what causes syncing is SyncAndGetError().
84 : *
85 : * This class is not thread-safe at all. It is assumed that only one thread is using any ScopedXErrorHandler's. Given that it's
86 : * not used on Mac, it should be easy to make it thread-safe by using thread-local storage with __thread.
87 : */
88 : class ScopedXErrorHandler
89 : {
90 : public:
91 : // trivial wrapper around XErrorEvent, just adding ctor initializing by zero.
92 : struct ErrorEvent
93 : {
94 : XErrorEvent mError;
95 :
96 3 : ErrorEvent()
97 3 : {
98 3 : memset(this, 0, sizeof(ErrorEvent));
99 3 : }
100 : };
101 :
102 : private:
103 :
104 : // this ScopedXErrorHandler's ErrorEvent object
105 : ErrorEvent mXError;
106 :
107 : // static pointer for use by the error handler
108 : static ErrorEvent* sXErrorPtr;
109 :
110 : // what to restore sXErrorPtr to on destruction
111 : ErrorEvent* mOldXErrorPtr;
112 :
113 : // what to restore the error handler to on destruction
114 : int (*mOldErrorHandler)(Display *, XErrorEvent *);
115 :
116 : public:
117 :
118 : static int
119 : ErrorHandler(Display *, XErrorEvent *ev);
120 :
121 : /**
122 : * @param aAllowOffMainThread whether to warn if used off main thread
123 : */
124 : explicit ScopedXErrorHandler(bool aAllowOffMainThread = false);
125 :
126 : ~ScopedXErrorHandler();
127 :
128 : /** \returns true if a X error occurred since the last time this method was called on this ScopedXErrorHandler object,
129 : * or since the creation of this ScopedXErrorHandler object if this method was never called on it.
130 : *
131 : * \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred,
132 : * the first one will be returned.
133 : */
134 : bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr);
135 : };
136 :
137 0 : class OffMainThreadScopedXErrorHandler : public ScopedXErrorHandler
138 : {
139 : public:
140 0 : OffMainThreadScopedXErrorHandler()
141 0 : : ScopedXErrorHandler(true)
142 : {
143 0 : }
144 : };
145 :
146 : } // namespace mozilla
147 :
148 : #endif // mozilla_X11Util_h
|