1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/src/X11Util.h Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,142 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 1.5 + * vim: sw=2 ts=8 et : 1.6 + */ 1.7 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.8 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.9 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.10 + 1.11 +#ifndef mozilla_X11Util_h 1.12 +#define mozilla_X11Util_h 1.13 + 1.14 +// Utilities common to all X clients, regardless of UI toolkit. 1.15 + 1.16 +#if defined(MOZ_WIDGET_GTK) 1.17 +# include <gdk/gdk.h> 1.18 +# include <gdk/gdkx.h> 1.19 +#elif defined(MOZ_WIDGET_QT) 1.20 +#include "gfxQtPlatform.h" 1.21 +#undef CursorShape 1.22 +# include <X11/Xlib.h> 1.23 +#else 1.24 +# error Unknown toolkit 1.25 +#endif 1.26 + 1.27 +#include <string.h> // for memset 1.28 +#include "gfxCore.h" // for NS_GFX 1.29 +#include "mozilla/Scoped.h" // for SCOPED_TEMPLATE 1.30 + 1.31 +namespace mozilla { 1.32 + 1.33 +/** 1.34 + * Return the default X Display created and used by the UI toolkit. 1.35 + */ 1.36 +inline Display* 1.37 +DefaultXDisplay() 1.38 +{ 1.39 +#if defined(MOZ_WIDGET_GTK) 1.40 + return GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); 1.41 +#elif defined(MOZ_WIDGET_QT) 1.42 + return gfxQtPlatform::GetXDisplay(); 1.43 +#endif 1.44 +} 1.45 + 1.46 +/** 1.47 + * Sets *aVisual to point to aDisplay's Visual struct corresponding to 1.48 + * aVisualID, and *aDepth to its depth. When aVisualID is None, these are set 1.49 + * to nullptr and 0 respectively. Both out-parameter pointers are assumed 1.50 + * non-nullptr. 1.51 + */ 1.52 +void 1.53 +FindVisualAndDepth(Display* aDisplay, VisualID aVisualID, 1.54 + Visual** aVisual, int* aDepth); 1.55 + 1.56 + 1.57 +/** 1.58 + * Ensure that all X requests have been processed. 1.59 + * 1.60 + * This is similar to XSync, but doesn't need a round trip if the previous 1.61 + * request was synchronous or if events have been received since the last 1.62 + * request. Subsequent FinishX calls will be noops if there have been no 1.63 + * intermediate requests. 1.64 + */ 1.65 + 1.66 +void 1.67 +FinishX(Display* aDisplay); 1.68 + 1.69 +/** 1.70 + * Invoke XFree() on a pointer to memory allocated by Xlib (if the 1.71 + * pointer is nonnull) when this class goes out of scope. 1.72 + */ 1.73 +template <typename T> 1.74 +struct ScopedXFreePtrTraits 1.75 +{ 1.76 + typedef T *type; 1.77 + static T *empty() { return nullptr; } 1.78 + static void release(T *ptr) { if (ptr != nullptr) XFree(ptr); } 1.79 +}; 1.80 +SCOPED_TEMPLATE(ScopedXFree, ScopedXFreePtrTraits) 1.81 + 1.82 +/** 1.83 + * On construction, set a graceful X error handler that doesn't crash the application and records X errors. 1.84 + * On destruction, restore the X error handler to what it was before construction. 1.85 + * 1.86 + * The SyncAndGetError() method allows to know whether a X error occurred, optionally allows to get the full XErrorEvent, 1.87 + * and resets the recorded X error state so that a single X error will be reported only once. 1.88 + * 1.89 + * Nesting is correctly handled: multiple nested ScopedXErrorHandler's don't interfere with each other's state. However, 1.90 + * if SyncAndGetError is not called on the nested ScopedXErrorHandler, then any X errors caused by X calls made while the nested 1.91 + * ScopedXErrorHandler was in place may then be caught by the other ScopedXErrorHandler. This is just a result of X being 1.92 + * asynchronous and us not doing any implicit syncing: the only method in this class what causes syncing is SyncAndGetError(). 1.93 + * 1.94 + * This class is not thread-safe at all. It is assumed that only one thread is using any ScopedXErrorHandler's. Given that it's 1.95 + * not used on Mac, it should be easy to make it thread-safe by using thread-local storage with __thread. 1.96 + */ 1.97 +class NS_GFX ScopedXErrorHandler 1.98 +{ 1.99 +public: 1.100 + // trivial wrapper around XErrorEvent, just adding ctor initializing by zero. 1.101 + struct ErrorEvent 1.102 + { 1.103 + XErrorEvent mError; 1.104 + 1.105 + ErrorEvent() 1.106 + { 1.107 + memset(this, 0, sizeof(ErrorEvent)); 1.108 + } 1.109 + }; 1.110 + 1.111 +private: 1.112 + 1.113 + // this ScopedXErrorHandler's ErrorEvent object 1.114 + ErrorEvent mXError; 1.115 + 1.116 + // static pointer for use by the error handler 1.117 + static ErrorEvent* sXErrorPtr; 1.118 + 1.119 + // what to restore sXErrorPtr to on destruction 1.120 + ErrorEvent* mOldXErrorPtr; 1.121 + 1.122 + // what to restore the error handler to on destruction 1.123 + int (*mOldErrorHandler)(Display *, XErrorEvent *); 1.124 + 1.125 +public: 1.126 + 1.127 + static int 1.128 + ErrorHandler(Display *, XErrorEvent *ev); 1.129 + 1.130 + ScopedXErrorHandler(); 1.131 + 1.132 + ~ScopedXErrorHandler(); 1.133 + 1.134 + /** \returns true if a X error occurred since the last time this method was called on this ScopedXErrorHandler object, 1.135 + * or since the creation of this ScopedXErrorHandler object if this method was never called on it. 1.136 + * 1.137 + * \param ev this optional parameter, if set, will be filled with the XErrorEvent object. If multiple errors occurred, 1.138 + * the first one will be returned. 1.139 + */ 1.140 + bool SyncAndGetError(Display *dpy, XErrorEvent *ev = nullptr); 1.141 +}; 1.142 + 1.143 +} // namespace mozilla 1.144 + 1.145 +#endif // mozilla_X11Util_h