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